/*	Simple test cases for the threads assignment.*/
/**/
#include "copyright.h"
#include "syscall.h"

#define MAX_CASHIERS 5
#define MAX_GOODS_LOADERS 5
#define MAX_SALESMAN 3
#define MAX_DEPARTMENTS 5
#define MAX_CUSTOMERS 30

/*=================================================//*/
/*---------------------STRUCTS---------------------//*/
/*=================================================//*/
/*
	All of our structs will go here, Will be broken
	down into smaller sections
*/

/*////////////////////*/
/*Humans*/
/*////////////////////*/
typedef struct Trolly{
	/*All trolly data goes here*/
	int itemList[MAX_DEPARTMENTS];
} Trolly;

typedef struct Customer{
	/*All customer data goes here*/
	int identifier;
	int privileged; /*0 = not, 1 = privileged*/
	int itemList[MAX_DEPARTMENTS]; /*up to MAX_DEPARTMENTS*/
	Trolly trolly;
	int money;
	int bill;
	int cashierID;
	int numItemsOnList;
	int canPay;
	int readyToNegotiate;
} Customer;

typedef struct Cashier{
	/*All cashier data goes here*/
	int identifier;
	int goOnBreak; /*0 = do not go on break, 1 = go on break when current customer has been served*/
	int onBreak; /*0 = not on break, 1 = on break //used by customers to determine whether they are being called forward or told to disperse*/
	int servingCustomer; /*0 = free, 1 = currently serving customer*/
	int cashierLineCount;
	int cashierPrivilegedLineCount;
	int customerID;
	
	int checkOrModifyLinesLock;
	int cashierLock;
	int cashierCV;
	int cashierLineLock;
	int cashierLineCV;
	int cashierPrivilegedLineLock;
	int cashierPrivilegedLineCV;
} Cashier;

typedef struct GoodsLoader{
	/*All goods loader data goes here*/
	int identifier;
	int departmentToRestock;
	int itemToRestock;
	int salesmanToNotifyAfterRestock;
	int numberOfItems;
	/*int goodsLoaderLock;*/
	int goodsLoaderCV;
} GoodsLoader;

typedef struct Salesman{
	/*All salesman data goes here*/
	int identifier;
	int departmentNumber;
	int goOnBreak;
	int salesmanLock;
	int salesmanCV;
	int salesmanOnBreakCV;
} Salesman;

typedef struct Manager{
	/*All manager data goes here*/
	int currentCashierID;
	int totalSales;
	int itemToRemove;
	int steps;
	int stepsUntilEmptyingDrawers;
	int stepsUntilStatingTotalSales;
	int stepsUntilSendingCashierOnBreak;
	int stepsUntilSendingSalesmanOnBreak;
	int managerLock;
	int managerCV;
	int managerCashierLineCV;
	int managerCashierHelpCV;
} Manager;

/*////////////////////*/
/*Department Utilities*/
/*////////////////////*/
typedef struct CheckoutCounter{
	/*All cashiers counter data goes here*/
	int identifier;
	int moneyInDrawer;
	int totalCounterSales;
	int drawerLock;
} CheckoutCounter;

typedef struct Department{
	/*All department data goes here*/
	int identifier;
	Salesman listOfSalesman[MAX_SALESMAN];
	int numberOfItems;
	int customerWaitingLineCount;
	int goodsLoaderWaitingLineCount;
	int restockAlreadyRequested;
	int salesCustIdentifier[MAX_SALESMAN];
	int salesLoaderIdentifier[MAX_SALESMAN];
	/*This is the array that stores which type of person the salesman is currently talking to
	0 = Greeting Customer, 1 = Complaining Customer, 2 = Goods Loader*/
	int whomITalkTo[3];
	int shelfLock;
	int goodsLoaderWaitingForSalesLock;
	int custWaitingForSalesLock;
	int restockAlreadyRequestedLock;
	int departmentRestockLock;
	int shelfCV;
	int goodsLoaderWaitingForSalesCV;
	int custWaitingForSalesCV;
	int custWaitingForRestockCV;
	/*This is the status array of all salesmen in the department. 
	0 = FREE, 1 = BUSY, 2 = ONBREAK, 3 = READY TO SPEAK TO A CUSTOMER */
	int salesStatusArray[MAX_SALESMAN]; 
} Department;
/*=================================================//*/
/*------------------(END) STRUCTS------------------//*/
/*=================================================//*/

/*=================================================//*/
/*-----------------GLOBAL DATA---------------------//*/
/*=================================================//*/
/*
	All of our globals will go here, Will be broken
	down into smaller sections
*/
	Manager manager;
	Customer customerArray[MAX_CUSTOMERS];
	Department departmentArray[MAX_DEPARTMENTS];
	Cashier cashierArray[MAX_CASHIERS];
	int stockRoomLock;
	int goodsLoaderInStockRoom = -1;
	CheckoutCounter checkoutCounterArray[MAX_CASHIERS];
	GoodsLoader goodsLoaderArray[MAX_GOODS_LOADERS];
	int pricesOfItems[MAX_DEPARTMENTS];
	int MIN_PRICE = 1;
	int MAX_PRICE = 5;
	int trollyLineLock;
	int trollyLineCV;
	int numTrolly = 20;
	int cashierLinesLock;
	int salesLoaderRestockLock;
	int idLock;
	/*This is the status array of all goodsloaders. 
	0 = FREE, 1 = NEEDS TO GO TO STOCKROOM, 2 = IN STOCKROOM, 3 = WALKING TO DEPARTMENT, 4 = NEEDS TO RESTOCK SHELF, 5 = NEEDS TO NOTIFY SALESMAN, 6 = SALESMAN NOTIFIED */
	int goodsLoaderStatus[MAX_GOODS_LOADERS];
	int salesmanOrderedRestock[MAX_GOODS_LOADERS];
	int whichDepartmentToRestock[MAX_GOODS_LOADERS];
	int remainingCustomers;
	int departmentsToRestock[MAX_DEPARTMENTS];
	int customerIDCount = 0;
	int salesmanIDCount = 0;
	int departmentIDCount = 0;
	int cashierIDCount = 0;
	int goodsLoaderIDCount = 0;
	
	
	int NUM_CASHIERS;
	int NUM_GOODS_LOADERS;
	int NUM_MANAGERS;
	int NUM_SALESMAN;
	int NUM_DEPARTMENTS;
	int NUM_TOTAL_CUSTOMERS;
	int NUM_ITEMS_ON_SHELF;
	int CUSTOMER_MONEY;
	
	int NUM_PRIVILEGED_CUSTOMERS = 0; /*incremented by CustomerSetup*/
	int NUM_CUSTOMERS = 0; /*incremented by CustomerSetup*/
	int debugShowCustomerOutput = 0;
	int debugShowCashierOutput = 0;
	int debugShowSalesmanOutput = 0;
	int debugShowGoodsLoaderOutput = 0;
	int debugShowManagerOutput = 0;
/*=================================================//*/
/*--------------(END) GLOBAL DATA------------------//*/
/*=================================================//*/

/*=================================================//*/
/*-------------MISCELLANEOUS FUNCTIONS-------------//*/
/*=================================================//*/
	/*All of our miscellaneous functions will go here*/
	/*void debugPrint(char* debugOutput)
	{
		int showThisOutput = 1;
		/*switch(currentThread.getName()[3])
		{
			case 't':
				if (!debugShowCustomerOutput)
					showThisOutput = 0;
				break;
			case 'h':
				if (!debugShowCashierOutput)
					showThisOutput = 0;
				break;
			case 'e':
				if (!debugShowSalesmanOutput)
					showThisOutput = 0;
				break;
			case 'd':
				if (!debugShowGoodsLoaderOutput)
					showThisOutput = 0;
				break;
			case 'a':
				if (!debugShowManagerOutput)
					showThisOutput = 0;
				break;
			default:
				/*printzf("\n~~DEBUG output from unknown thread!~~\n\n");*/
				/*break;
		}*/
		/*if (showThisOutput)
			printzf("~~DEBUG: {%s}: \"%s\"\n",currentThread.getName(),debugOutput);*/
	/*}
	void debugPrint(char* debugOutput, int debugInt)
	{
		int showThisOutput = 1;
		/*switch(currentThread.getName()[3])
		{
			case 't':
				if (!debugShowCustomerOutput)
					showThisOutput = 0;
				break;
			case 'h':
				if (!debugShowCashierOutput)
					showThisOutput = 0;
				break;
			case 'e':
				if (!debugShowSalesmanOutput)
					showThisOutput = 0;
				break;
			case 'd':
				if (!debugShowGoodsLoaderOutput)
					showThisOutput = 0;
				break;
			case 'a':
				if (!debugShowManagerOutput)
					showThisOutput = 0;
				break;
			default:
				/*printzf("\n~~DEBUG output from unknown thread!~~\n\n");*/
				/*break;
		}*/
		/*if (showThisOutput)
			printzf("~~DEBUG: {%s}: \"%s {%d}\"\n",currentThread.getName(),debugOutput,debugInt);*/
	/*}
	void debugPrint(char* debugOutput, int debugInt,int debugInt2)
	{
		int showThisOutput = 1;
		/*switch(currentThread.getName()[3])
		{
			case 't':
				if (!debugShowCustomerOutput)
					showThisOutput = 0;
				break;
			case 'h':
				if (!debugShowCashierOutput)
					showThisOutput = 0;
				break;
			case 'e':
				if (!debugShowSalesmanOutput)
					showThisOutput = 0;
				break;
			case 'd':
				if (!debugShowGoodsLoaderOutput)
					showThisOutput = 0;
				break;
			case 'a':
				if (!debugShowManagerOutput)
					showThisOutput = 0;
				break;
			default:
				/*printzf("\n~~DEBUG output from unknown thread!~~\n\n");*/
				/*break;
		}*/
		/*if (showThisOutput)
			printzf("~~DEBUG: {%s}: \"%s {%d, %d}\"\n",currentThread.getName(),debugOutput,debugInt,debugInt2);*/
	/*}*/
	void convertToDollarsAndCents(int totalCents)
	{
		int dollars = totalCents/100;
		int cents = (totalCents-((totalCents/100)*100));
		char dollarsAndCents[256];
		if (cents<10)
		{
			/*Sprintf(dollarsAndCents,"%d.0%d",sizeof("%d.0%d"),dollars*10000+cents);*/
			Print("%d.0%d", sizeof("%d.0%d"),dollars*10000+cents, -1);
		}
		else
		{
			/*Sprintf(dollarsAndCents,"%d.%d",sizeof("%d.%d"),dollars*10000+cents);*/
			Print("%d.%d",sizeof("%d.%d"),dollars*10000+cents, -1);
		}
		/*return dollarsAndCents;*/
	}
	void printEndOfSimulationOutputs()
	{
		int i, j, k;
		int totalSalesEOS = 0;
		/*allow goodsloaders to finish restocking things*/
		for (i = 0; i < NUM_GOODS_LOADERS; i++)
			if (goodsLoaderStatus[i] != 0)
				for (j = 0; j < 50; j++)
					Yield();
		
		for (i = 0; i < NUM_CASHIERS; i++)
				for (j = 0; j < 50; j++)
					Yield();
		
		for (k = 0; k < NUM_CASHIERS; k++)
		{
			totalSalesEOS += checkoutCounterArray[k].totalCounterSales;
			Print("Total Sale from Counter [%d] is $[", sizeof("Total Sale from Counter [%d] is $["), k*10000, -1);
			convertToDollarsAndCents(checkoutCounterArray[k].totalCounterSales);
			PrintString("].\n", sizeof("].\n"));
		}
		PrintString("Total Sale of the entire store is $[", sizeof("Total Sale of the entire store is $["));
		convertToDollarsAndCents(totalSalesEOS);
		PrintString("].\n", sizeof("].\n"));
	}
	int randInt(int min, int max)
	{	
		return (Rand() % (max - min + 1) + min); /*returns a random int in the specified range*/
	}
/*=================================================//*/
/*---------(END) MISCELLANEOUS FUNCTIONS-----------//*/
/*=================================================//*/

/*=================================================//*/
/*------------------CUSTOMER-----------------------//*/
/*=================================================//*/
void CustomerSetup(int id){ /*called when initializing a new Customer*/
	int i;
	int itemType;
	
	customerArray[id].identifier = id;
	
	/*1 in 5 chance of a customer being privileged*/
	if(randInt(1, 5) != 1)
	{
		customerArray[id].privileged = 0;
		NUM_CUSTOMERS++;
	}
	else
	{
		customerArray[id].privileged = 1;
		NUM_PRIVILEGED_CUSTOMERS++;
	}
	
	customerArray[id].money = CUSTOMER_MONEY;
	customerArray[id].cashierID = -1;
	customerArray[id].canPay = 1;
	customerArray[id].readyToNegotiate = 0;
	
	/*populate customer's item list*/
	customerArray[id].numItemsOnList = randInt(1, 10);
	for(i = 0; i < customerArray[id].numItemsOnList; i++)
	{
		/*Print("NUMBER OF ITEMS ON LIST: %d, CUST ID: %d", sizeof("NUMBER OF ITEMS ON LIST: %d, CUST ID: %d"), customerArray[id].numItemsOnList*10000+id, -1);*/
		itemType = randInt(0, 1);/*NUM_DEPARTMENTS-1);*/
		customerArray[id].itemList[itemType]++;
	}
	
}

void CustomerFunction(){
	int i, j, id, waitInLine, waitInLineForRestock, lookingForCashier;
	AcquireLock(idLock);
	id = customerIDCount;
	customerIDCount++;
	ReleaseLock(idLock);
	
	/*print that customer has entered*/
	if(customerArray[id].privileged)
		Print("PrivilegedCustomer [%d] enters the SuperMarket\n",sizeof("PrivilegedCustomer [%d] enters the SuperMarket\n"), id*10000,-1);
	else
		Print("Customer [%d] enters the SuperMarket\n",sizeof("Customer [%d] enters the SuperMarket\n"), id*10000,-1);
	
	/*print how many items the customer wants to buy*/
	if(customerArray[id].privileged)
		Print("PrivilegedCustomer [%d] wants to buy [%d] no.of items.\n",sizeof("PrivilegedCustomer [%d] wants to buy [%d] no.of items.\n"), id*10000+ customerArray[id].numItemsOnList,-1);
	else
		Print("Customer [%d] wants to buy [%d] no.of items.\n",sizeof("Customer [%d] wants to buy [%d] no.of items.\n"), id*10000+ customerArray[id].numItemsOnList,-1);
	
	/*print how many of each type of item the customer wants to buy*/
	for(i = 0; i < NUM_DEPARTMENTS; i++)
	{
		if(customerArray[id].itemList[i] > 0)
		{
			if(customerArray[id].privileged)
				Print("PrivilegedCustomer [%d] wants to buy [item%d]-[%d].\n",sizeof("PrivilegedCustomer [%d] wants to buy [item%d]-[%d].\n"), id*10000+ i, customerArray[id].itemList[i]*10000);
			else
				Print("Customer [%d] wants to buy [item%d]-[%d].\n",sizeof("Customer [%d] wants to buy [item%d]-[%d].\n"), id*10000+ i, customerArray[id].itemList[i]*10000);
		}
	}
	
	/*wait in line for a trolly if necessary*/
	AcquireLock(trollyLineLock);
	if(numTrolly == 0)
	{
		if(customerArray[id].privileged)
			Print("PrivilegedCustomer [%d] gets in line for a trolly\n",sizeof("PrivilegedCustomer [%d] gets in line for a trolly\n"), id*10000,-1);
		else
			Print("Customer [%d] gets in line for a trolly\n",sizeof("Customer [%d] gets in line for a trolly\n"), id*10000,-1);
		WaitCondition(trollyLineCV,trollyLineLock);
	}
	
	/*get and initialize the customer's trolly*/
	if(customerArray[id].privileged)
		Print("PrivilegedCustomer [%d] has a trolly for shopping\n",sizeof("PrivilegedCustomer [%d] has a trolly for shopping\n"), id*10000,-1);
	else
		Print("Customer [%d] has a trolly for shopping\n",sizeof("Customer [%d] has a trolly for shopping\n"), id*10000,-1);
	numTrolly--;
	ReleaseLock(trollyLineLock);
	for(i = 0; i < NUM_DEPARTMENTS; i++)
	{
		customerArray[id].trolly.itemList[i] = 0;
	}
	
	/*find each item on list*/
	for(i = 0; i < NUM_DEPARTMENTS; i++)
	{
		/*if the item type is on the customer's list they must go to that department*/
		if(customerArray[id].itemList[i] > 0)
		{
			/*print which department the customer is headed to*/
			if(customerArray[id].privileged)
				Print("PrivilegedCustomer [%d] wants to shop in Department[%d]\n",sizeof("PrivilegedCustomer [%d] wants to shop in Department[%d]\n"), id*10000+ i,-1);
			else
				Print("Customer [%d] wants to shop in Department[%d]\n",sizeof("Customer [%d] wants to shop in Department[%d]\n"), id*10000+ i,-1);
			
			/*find a salesman*/
			AcquireLock(departmentArray[i].custWaitingForSalesLock);
			waitInLine = 1;
			for(j = 0; j < NUM_SALESMAN; j++) /*check with each department salesman*/
			{
				/*if there is a free salesman, begin interaction with that salesman and skip the line*/
				AcquireLock(departmentArray[i].listOfSalesman[j].salesmanLock);
				/*debugPrint("Checking sales status %d, customerWaitingLineCount %d",departmentArray[i].salesStatusArray[j], departmentArray[i].customerWaitingLineCount);*/
				if(departmentArray[i].salesStatusArray[j] == 0 && departmentArray[i].customerWaitingLineCount == 0 && departmentArray[i].listOfSalesman[j].goOnBreak == 0)
				{
					waitInLine = 0;
					departmentArray[i].salesStatusArray[j] = 1;
					departmentArray[i].salesCustIdentifier[j] = id;
					departmentArray[i].whomITalkTo[j] = 0;
					ReleaseLock(departmentArray[i].custWaitingForSalesLock);
					if(customerArray[id].privileged)
						Print("PrivilegedCustomer [%d] is interacting with DepartmentSalesman[%d] of Department[%d]\n",sizeof("PrivilegedCustomer [%d] is interacting with DepartmentSalesman[%d] of Department[%d]\n"), id*10000+ j, i*10000);
					else
						Print("Customer [%d] is interacting with DepartmentSalesman[%d] of Department[%d]\n",sizeof("Customer [%d] is interacting with DepartmentSalesman[%d] of Department[%d]\n"), id*10000+ j, i*10000);
					/*debugPrint("-A- signaling salesmanlock %d",departmentArray[i].salesStatusArray[j]);*/
					SignalCondition(departmentArray[i].listOfSalesman[j].salesmanCV,departmentArray[i].listOfSalesman[j].salesmanLock);
					/*debugPrint("-A- waiting on salesmanlock %d",departmentArray[i].salesStatusArray[j]);*/
					WaitCondition(departmentArray[i].listOfSalesman[j].salesmanCV,departmentArray[i].listOfSalesman[j].salesmanLock);
					/*debugPrint("woken on salesmanlock");*/
					/*debugPrint("Setting salesman status.");*/
					departmentArray[i].salesStatusArray[j] = 0;
					/*debugPrint("salesman status set.");*/
					ReleaseLock(departmentArray[i].listOfSalesman[j].salesmanLock);
					/*debugPrint("released salesmanlock");*/
					break;
				}
				else
				{
					ReleaseLock(departmentArray[i].listOfSalesman[j].salesmanLock);
				}
				
			}
			
			/*if there was not a free salesman*/
			if(waitInLine)
			{
				/*get in line and wait to be called up by a salesman*/
				for(j = 0; j < NUM_SALESMAN; j++)
				{
					AcquireLock(departmentArray[i].listOfSalesman[j].salesmanLock);
				}
				departmentArray[i].customerWaitingLineCount++;
				/*debugPrint("Incremented customerWaitingLineCount to ",departmentArray[i].customerWaitingLineCount);*/
				if(customerArray[id].privileged)
					Print("PrivilegedCustomer [%d] gets in line for the Department [%d]\n",sizeof("PrivilegedCustomer [%d] gets in line for the Department [%d]\n"), id*10000+ i,-1);
				else
					Print("Customer [%d] gets in line for the Department [%d]\n",sizeof("Customer [%d] gets in line for the Department [%d]\n"), id*10000+ i,-1);
				for(j = 0; j < NUM_SALESMAN; j++)
				{
					ReleaseLock(departmentArray[i].listOfSalesman[j].salesmanLock);
				}
				WaitCondition(departmentArray[i].custWaitingForSalesCV,departmentArray[i].custWaitingForSalesLock);
				/*debugPrint("waiting in line has woken up.");*/
				/*check with each department salesman*/
				for(j = 0; j < NUM_SALESMAN; j++)
				{
					/*if the corresponding department salesman is the one who called the customer up, begin interacting with the salesman*/
					AcquireLock(departmentArray[i].listOfSalesman[j].salesmanLock);
					/*debugPrint("checking salesman status: salesman status =%d.", departmentArray[i].salesStatusArray[j]);*/
					if((departmentArray[i].salesStatusArray[j] == 3 || departmentArray[i].salesStatusArray[j] == 0 ) && departmentArray[i].whomITalkTo[j] != 2 && departmentArray[i].listOfSalesman[j].goOnBreak == 0)
					{
						
						
						departmentArray[i].salesStatusArray[j] = 1;
						departmentArray[i].salesCustIdentifier[j] = id;
						departmentArray[i].whomITalkTo[j] = 0;
						ReleaseLock(departmentArray[i].custWaitingForSalesLock);
						if(customerArray[id].privileged)
							Print("PrivilegedCustomer [%d] is interacting with DepartmentSalesman[%d] of Department[%d]\n",sizeof("PrivilegedCustomer [%d] is interacting with DepartmentSalesman[%d] of Department[%d]\n"), id*10000+ j, i*10000);
						else
							Print("Customer [%d] is interacting with DepartmentSalesman[%d] of Department[%d]\n",sizeof("Customer [%d] is interacting with DepartmentSalesman[%d] of Department[%d]\n"), id*10000+ j, i*10000);
						/*debugPrint("-B- signaling salesmanlock %d",departmentArray[i].salesStatusArray[j]);*/
						SignalCondition(departmentArray[i].listOfSalesman[j].salesmanCV,departmentArray[i].listOfSalesman[j].salesmanLock);
						/*debugPrint("-B- waiting on salesmanlock %d",departmentArray[i].salesStatusArray[j]);*/
						WaitCondition(departmentArray[i].listOfSalesman[j].salesmanCV,departmentArray[i].listOfSalesman[j].salesmanLock);
						/*debugPrint("Setting salesman status.");*/
						departmentArray[i].salesStatusArray[j] = 0;
						/*debugPrint("salesman status set.");*/
						ReleaseLock(departmentArray[i].listOfSalesman[j].salesmanLock);
						break;
					}
					else
					{
						ReleaseLock(departmentArray[i].listOfSalesman[j].salesmanLock);
					}
				}
			}
			
			while(customerArray[id].itemList[i] > 0)
			{
				/*access the shelf with the item the customer is looking for*/
				AcquireLock(departmentArray[i].shelfLock);
				if(customerArray[id].itemList[i] <= departmentArray[i].numberOfItems) /*if the shelf has enough of the item that the customer wants*/
				{
					/*take the item off the shelf and put it in the trolly*/
					departmentArray[i].numberOfItems -= customerArray[id].itemList[i];
					customerArray[id].trolly.itemList[i] += customerArray[id].itemList[i];
					if(customerArray[id].privileged)
						Print("PrivilegedCustomer [%d] has found [item%d] and placed [%d] in the trolly\n",sizeof("PrivilegedCustomer [%d] has found [item%d] and placed [%d] in the trolly\n"), id*10000+ i, customerArray[id].itemList[i]*10000);
					else
						Print("Customer [%d] has found [item%d] and placed [%d] in the trolly\n",sizeof("Customer [%d] has found [item%d] and placed [%d] in the trolly\n"), id*10000+ i, customerArray[id].itemList[i]*10000);
					customerArray[id].itemList[i] = 0;
					/*debugPrint("%d ITEMS ON SHELF", departmentArray[i].numberOfItems);*/
					ReleaseLock(departmentArray[i].shelfLock);
				}
				else /*if the shelf does not have enough of the item that the customer wants*/
				{
					/*take as many of that item as there are on that shelf*/
					if(departmentArray[i].numberOfItems > 0)
					{
						customerArray[id].trolly.itemList[i] += departmentArray[i].numberOfItems;
						customerArray[id].itemList[i] -= departmentArray[i].numberOfItems;
						if(customerArray[id].privileged)
							Print("PrivilegedCustomer [%d] has found [item%d] and placed [%d] in the trolly\n",sizeof("PrivilegedCustomer [%d] has found [item%d] and placed [%d] in the trolly\n"), id*10000+ i, departmentArray[i].numberOfItems*10000);
						else
							Print("Customer [%d] has found [item%d] and placed [%d] in the trolly\n",sizeof("Customer [%d] has found [item%d] and placed [%d] in the trolly\n"), id*10000+ i, departmentArray[i].numberOfItems*10000);
						departmentArray[i].numberOfItems = 0;
						/*debugPrint("%d ITEMS ON SHELF", departmentArray[i].numberOfItems);*/
					}
					
					/*debugPrint("finding salesman to restock");*/
					/*find a salesman*/
					AcquireLock(departmentArray[i].custWaitingForSalesLock);
					/*debugPrint("acquired custwaitingforsaleslock");*/
					ReleaseLock(departmentArray[i].shelfLock);
					/*debugPrint("released shelflock");*/
					waitInLineForRestock = 1;
					for(j = 0; j < NUM_SALESMAN; j++) /*look through the salesmans*/
					{
						/*if there is a free salesman, tell him that the item the customer wants is out of stock and wait for it to be restocked*/
						
						AcquireLock(departmentArray[i].listOfSalesman[j].salesmanLock);
						/*debugPrint("-1- checking salesman %d, status %d",j,departmentArray[i].salesStatusArray[j]);*/
						if(departmentArray[i].salesStatusArray[j] == 0 && departmentArray[i].customerWaitingLineCount == 0 && departmentArray[i].listOfSalesman[j].goOnBreak == 0)
						{
							waitInLineForRestock = 0;
							
							AcquireLock(departmentArray[i].departmentRestockLock);
							departmentArray[i].salesStatusArray[j] = 1;
							departmentArray[i].salesCustIdentifier[j] = id;
							departmentArray[i].whomITalkTo[j] = 1;
							ReleaseLock(departmentArray[i].custWaitingForSalesLock);
							Print("Customer [%d] is asking for assistance from DepartmentSalesman [%d].\n",sizeof("Customer [%d] is asking for assistance from DepartmentSalesman [%d].\n"), id*10000+ j,-1);
							/*debugPrint("A: %d %d", i, j);*/
							SignalCondition(departmentArray[i].listOfSalesman[j].salesmanCV,departmentArray[i].listOfSalesman[j].salesmanLock);
							/*debugPrint("B");*/
							departmentArray[i].salesStatusArray[j] = 0;
							/*debugPrint("C");*/
							ReleaseLock(departmentArray[i].listOfSalesman[j].salesmanLock);
							WaitCondition(departmentArray[i].custWaitingForRestockCV,departmentArray[i].departmentRestockLock);
							/*debugPrint("D");*/
							ReleaseLock(departmentArray[i].departmentRestockLock);
							Print("Customer [%d] has received assistance about restocking of [item%d] from DepartmentSalesman [%d].\n",sizeof("Customer [%d] has received assistance about restocking of [item%d] from DepartmentSalesman [%d].\n"), id*10000+ i, j*10000);
							break;
						}
						else
						{
							ReleaseLock(departmentArray[i].listOfSalesman[j].salesmanLock);
						}
					}
					
					/*if there was not a free salesman*/
					if(waitInLineForRestock)
					{/*debugPrint("getting in line");*/
						/*get in line and wait to be called up by a salesman*/
						departmentArray[i].customerWaitingLineCount++;
						/*debugPrint("Incremented customerWaitingLineCount to ",departmentArray[i].customerWaitingLineCount);*/
						/*debugPrint("about to wait on custwaitingforsalescv, custwaitingforsaleslock");*/
						WaitCondition(departmentArray[i].custWaitingForSalesCV,departmentArray[i].custWaitingForSalesLock);
						/*debugPrint("about to woke up from custwaitingforsalescv, custwaitingforsaleslock");*/
						/*check with each department salesman*/
						for(j = 0; j < NUM_SALESMAN; j++)
						{
							/*if the corresponding department salesman is the one who called the customer up, tell them the item needs to be restocked and wait for it to be restocked*/
							
							AcquireLock(departmentArray[i].listOfSalesman[j].salesmanLock);
							/*debugPrint("-2- checking salesman %d, status %d",j,departmentArray[i].salesStatusArray[j]);*/
							if((departmentArray[i].salesStatusArray[j] == 3 || departmentArray[i].salesStatusArray[j] == 0 ) && departmentArray[i].whomITalkTo[j] != 2 && departmentArray[i].listOfSalesman[j].goOnBreak == 0)
							{
								
								AcquireLock(departmentArray[i].departmentRestockLock);
								departmentArray[i].salesStatusArray[j] = 1;
								departmentArray[i].salesCustIdentifier[j] = id;
								departmentArray[i].whomITalkTo[j] = 1;
								ReleaseLock(departmentArray[i].custWaitingForSalesLock);
								Print("Customer [%d] is asking for assistance from DepartmentSalesman [%d].\n",sizeof("Customer [%d] is asking for assistance from DepartmentSalesman [%d].\n"), id*10000+ j,-1);
								/*debugPrint("A2");*/
								SignalCondition(departmentArray[i].listOfSalesman[j].salesmanCV,departmentArray[i].listOfSalesman[j].salesmanLock);
								/*debugPrint("B2");*/
								departmentArray[i].salesStatusArray[j] = 0;
								/*debugPrint("C2");*/
								ReleaseLock(departmentArray[i].listOfSalesman[j].salesmanLock);
								WaitCondition(departmentArray[i].custWaitingForRestockCV,departmentArray[i].departmentRestockLock);
								/*debugPrint("D2");*/
								ReleaseLock(departmentArray[i].departmentRestockLock);
								Print("Customer [%d] has received assistance about restocking of [item%d] from DepartmentSalesman [%d].\n",sizeof("Customer [%d] has received assistance about restocking of [item%d] from DepartmentSalesman [%d].\n"), id*10000+ i, j*10000);
								break;
							}
							else
							{
								ReleaseLock(departmentArray[i].listOfSalesman[j].salesmanLock);
							}
						}
					}
				}	
			}
			
			/*print that the customer has finished in the current department*/
			if(customerArray[id].privileged)
				Print("PrivilegedCustomer [%d] has finished shopping in Department[%d]\n",sizeof("PrivilegedCustomer [%d] has finished shopping in Department[%d]\n"), id*10000+ i,-1);
			else
				Print("Customer [%d] has finished shopping in Department[%d]\n",sizeof("Customer [%d] has finished shopping in Department[%d]\n"), id*10000+ i,-1);
		}
	}
	
	lookingForCashier = 1;
	while(lookingForCashier)
	{
		/*debugPrint("acquiring cashierlineslock");*/
		/*acquire a lock to look through all of the cashiers' lines*/
		AcquireLock(cashierLinesLock);
		/*debugPrint("has acquired cashierlineslock");*/
		if(customerArray[id].privileged) /*if the customer is privileged*/
		{
			/*loop through all of the privileged lines and find the shortest one*/
			
			Print("PrivilegedCustomer [%d] is looking for the Cashier.\n",sizeof("PrivilegedCustomer [%d] is looking for the Cashier.\n"), id*10000,-1);
			
			for(i = 0; i < NUM_CASHIERS; i++)
			{/*debugPrint("A %d",i);*/
				AcquireLock(cashierArray[i].checkOrModifyLinesLock);
				if(i == 0)
					customerArray[id].cashierID = 0;
				else if((cashierArray[i].cashierPrivilegedLineCount + cashierArray[i].servingCustomer
						< cashierArray[customerArray[id].cashierID].cashierPrivilegedLineCount + cashierArray[customerArray[id].cashierID].servingCustomer
						&& !cashierArray[i].onBreak && !cashierArray[i].goOnBreak)
						|| ((cashierArray[customerArray[id].cashierID].onBreak||cashierArray[customerArray[id].cashierID].goOnBreak) && !cashierArray[i].onBreak && !cashierArray[i].goOnBreak))
					customerArray[id].cashierID = i;
				ReleaseLock(cashierArray[i].checkOrModifyLinesLock);
			}
			AcquireLock(cashierArray[customerArray[id].cashierID].cashierPrivilegedLineLock);	
			/*debugPrint("-A- releasing cashierlineslock");*/
			ReleaseLock(cashierLinesLock);
			/*debugPrint("-A- released cashierlineslock");*/
			AcquireLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
			Print("PrivilegedCustomer [%d] chose Cashier [%d] with line of length [%d].\n", sizeof("PrivilegedCustomer [%d] chose Cashier [%d] with line of length [%d].\n"), id*10000 + customerArray[id].cashierID,(cashierArray[customerArray[id].cashierID].cashierPrivilegedLineCount + cashierArray[customerArray[id].cashierID].servingCustomer)*10000);
			if (cashierArray[customerArray[id].cashierID].cashierPrivilegedLineCount + cashierArray[customerArray[id].cashierID].servingCustomer >0)
			{
				cashierArray[customerArray[id].cashierID].cashierPrivilegedLineCount++;
				ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
				/*debugPrint("GOING TO SLEEP, privCUSTOMER: %d", id);*/
				WaitCondition(cashierArray[customerArray[id].cashierID].cashierPrivilegedLineCV,cashierArray[customerArray[id].cashierID].cashierPrivilegedLineLock);
				/*debugPrint("CASHIER WOKE ME UP, privCUSTOMER: %d", id);*/
				AcquireLock(cashierArray[customerArray[id].cashierID].cashierLock);
				AcquireLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
				if(!cashierArray[customerArray[id].cashierID].onBreak && !cashierArray[customerArray[id].cashierID].goOnBreak)
				{
					/*AcquireLock(cashierArray[customerArray[id].cashierID].cashierLock);*/
					/*cashierArray[customerArray[id].cashierID].cashierPrivilegedLineCount++;*/
					lookingForCashier = 0;
					cashierArray[customerArray[id].cashierID].servingCustomer = 1;
					cashierArray[customerArray[id].cashierID].customerID = id; /*give trolly (customer id) to cashier*/
					cashierArray[customerArray[id].cashierID].cashierPrivilegedLineCount--;
					ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
				}
				else
				{
					/*debugPrint("this cashier (%d) is going on break, need to find a new one.",customerArray[id].cashierID);*/
					ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
					ReleaseLock(cashierArray[customerArray[id].cashierID].cashierLock);
				}
				ReleaseLock(cashierArray[customerArray[id].cashierID].cashierPrivilegedLineLock);
				/*debugPrint("CASHIER WOKE ME UP, privCUSTOMER: %d", id);*/
			}
			else if(!cashierArray[customerArray[id].cashierID].onBreak && !cashierArray[customerArray[id].cashierID].goOnBreak)
			{
				cashierArray[customerArray[id].cashierID].servingCustomer = 1;
				/*lookingForCashier = 0;*/
				/*cashierArray[customerArray[id].cashierID].cashierPrivilegedLineCount++;*/
				ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
				/*debugPrint("ABOUT TO ACQUIRE, privCUSTOMER: %d", id);*/
				AcquireLock(cashierArray[customerArray[id].cashierID].cashierLock);
				AcquireLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
				if (!cashierArray[customerArray[id].cashierID].onBreak && !cashierArray[customerArray[id].cashierID].goOnBreak)
				{
					lookingForCashier = 0;
					/*cashierArray[customerArray[id].cashierID].cashierPrivilegedLineCount++;*/
					cashierArray[customerArray[id].cashierID].servingCustomer = 1;
					cashierArray[customerArray[id].cashierID].customerID = id; /*give trolly (customer id) to cashier*/
					/*cashierArray[customerArray[id].cashierID].cashierPrivilegedLineCount--;*/
					ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
				}
				else
				{
					cashierArray[customerArray[id].cashierID].servingCustomer = 0;
					/*debugPrint("this cashier (%d) is going on break, need to find a new one.",customerArray[id].cashierID);*/
					ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
					ReleaseLock(cashierArray[customerArray[id].cashierID].cashierLock);
				}
				/*debugPrint("releasing cashierprivLINElock");*/
				ReleaseLock(cashierArray[customerArray[id].cashierID].cashierPrivilegedLineLock);
				/*debugPrint("released cashierprivLINElock");*/
				/*SignalCondition(cashierArray[customerArray[id].cashierID].cashierCV,cashierArray[customerArray[id].cashierID].cashierLock);*/
			}
			else
			{
				ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
				/*debugPrint("releasing cashierprivLINElock");*/
				ReleaseLock(cashierArray[customerArray[id].cashierID].cashierPrivilegedLineLock);
				/*debugPrint("released cashierprivLINElock");*/
			}
			
			/*if(!cashierArray[customerArray[id].cashierID].onBreak && !cashierArray[customerArray[id].cashierID].goOnBreak)
			{
				AcquireLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
				cashierArray[customerArray[id].cashierID].servingCustomer = 1;
				cashierArray[customerArray[id].cashierID].customerID = id; //give trolly (customer id) to cashier
				cashierArray[customerArray[id].cashierID].cashierPrivilegedLineCount--;
				ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
			}*/
		}
		else /*if the customer is not privileged*/
		{
			/*loop through all of the cashier's total line sizes (the sum of a cashier's regular line and privileged line) and find one with the shortest total*/
			Print("Customer [%d] is looking for the Cashier.\n",sizeof("Customer [%d] is looking for the Cashier.\n"), id*10000,-1);
			for(i = 0; i < NUM_CASHIERS; i++)
			{/*debugPrint("B %d",i);*/
				AcquireLock(cashierArray[i].checkOrModifyLinesLock);
				if(i == 0)
					customerArray[id].cashierID = 0;
				else if((cashierArray[i].cashierLineCount + cashierArray[i].cashierPrivilegedLineCount + cashierArray[i].servingCustomer
						< cashierArray[customerArray[id].cashierID].cashierLineCount + cashierArray[customerArray[id].cashierID].cashierPrivilegedLineCount + cashierArray[customerArray[id].cashierID].servingCustomer
						&& !cashierArray[i].onBreak && !cashierArray[i].goOnBreak)
						|| ((cashierArray[customerArray[id].cashierID].onBreak||cashierArray[customerArray[id].cashierID].goOnBreak) && !cashierArray[i].onBreak && !cashierArray[i].goOnBreak) )
				{
					customerArray[id].cashierID = i;
				}
				ReleaseLock(cashierArray[i].checkOrModifyLinesLock);
			}
			/*debugPrint("acquiring cashierLINElock");*/
			AcquireLock(cashierArray[customerArray[id].cashierID].cashierLineLock);
			/*debugPrint("acquired cashierLINElock");*/
			/*debugPrint("-B- releasing cashierlineslock");*/
			ReleaseLock(cashierLinesLock);
			/*debugPrint("-B- released cashierlineslock");*/
			AcquireLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
			Print("Customer [%d] chose Cashier [%d] with line of length [%d].\n", sizeof("Customer [%d] chose Cashier [%d] with line of length [%d].\n"), id*10000 + customerArray[id].cashierID, (cashierArray[customerArray[id].cashierID].cashierLineCount + cashierArray[customerArray[id].cashierID].cashierPrivilegedLineCount + cashierArray[customerArray[id].cashierID].servingCustomer)*10000);
			if ((cashierArray[customerArray[id].cashierID].cashierLineCount + cashierArray[customerArray[id].cashierID].cashierPrivilegedLineCount + cashierArray[customerArray[id].cashierID].servingCustomer)>0)
			{
				cashierArray[customerArray[id].cashierID].cashierLineCount++;
				ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
				/*debugPrint("waiting on cashierlineCV, cashierLINElock");*/
				WaitCondition(cashierArray[customerArray[id].cashierID].cashierLineCV,cashierArray[customerArray[id].cashierID].cashierLineLock);
				/*debugPrint("woke up from cashierlineCV, cashierLINElock");*/
				AcquireLock(cashierArray[customerArray[id].cashierID].cashierLock);
				AcquireLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
				if(!cashierArray[customerArray[id].cashierID].onBreak && !cashierArray[customerArray[id].cashierID].goOnBreak)
				{
					/*AcquireLock(cashierArray[customerArray[id].cashierID].cashierLock);*/
					/*cashierArray[customerArray[id].cashierID].cashierLineCount++;*/
					lookingForCashier = 0;
					cashierArray[customerArray[id].cashierID].servingCustomer = 1;
					cashierArray[customerArray[id].cashierID].customerID = id; /*give trolly (customer id) to cashier*/
					cashierArray[customerArray[id].cashierID].cashierLineCount--;
					ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
				}
				else
				{
					/*debugPrint("this cashier (%d) is going on break, need to find a new one.",customerArray[id].cashierID);*/
					ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
					ReleaseLock(cashierArray[customerArray[id].cashierID].cashierLock);
				}
				ReleaseLock(cashierArray[customerArray[id].cashierID].cashierLineLock);				
			}
			else if(!cashierArray[customerArray[id].cashierID].onBreak && !cashierArray[customerArray[id].cashierID].goOnBreak)
			{
				cashierArray[customerArray[id].cashierID].servingCustomer = 1;
				/*lookingForCashier = 0;*/
				/*cashierArray[customerArray[id].cashierID].cashierLineCount++;*/
				ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
				/*debugPrint("ABOUT TO ACQUIRE, CUSTOMER: %d", id);*/
				AcquireLock(cashierArray[customerArray[id].cashierID].cashierLock);
				AcquireLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
				if (!cashierArray[customerArray[id].cashierID].onBreak && !cashierArray[customerArray[id].cashierID].goOnBreak)
				{
					lookingForCashier = 0;
					/*cashierArray[customerArray[id].cashierID].cashierLineCount++;*/
					cashierArray[customerArray[id].cashierID].servingCustomer = 1;
					cashierArray[customerArray[id].cashierID].customerID = id; /*give trolly (customer id) to cashier*/
					/*cashierArray[customerArray[id].cashierID].cashierLineCount--;*/
					ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
				}
				else
				{
					cashierArray[customerArray[id].cashierID].servingCustomer = 0;
					/*debugPrint("this cashier (%d) is going on break, need to find a new one.",customerArray[id].cashierID);*/
					ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
					ReleaseLock(cashierArray[customerArray[id].cashierID].cashierLock);
				}
				/*debugPrint("releasing cashierLINElock");*/
				ReleaseLock(cashierArray[customerArray[id].cashierID].cashierLineLock);
				/*debugPrint("released cashierLINElock");*/
				/*SignalCondition(cashierArray[customerArray[id].cashierID].cashierCV,cashierArray[customerArray[id].cashierID].cashierLock);*/
			}
			else
			{
				ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
				/*debugPrint("releasing cashierLINElock");*/
				ReleaseLock(cashierArray[customerArray[id].cashierID].cashierLineLock);
				/*debugPrint("released cashierLINElock");*/
			}
			
			/*if(!cashierArray[customerArray[id].cashierID].onBreak && !cashierArray[customerArray[id].cashierID].goOnBreak)
			{
				AcquireLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
				cashierArray[customerArray[id].cashierID].servingCustomer = 1;
				cashierArray[customerArray[id].cashierID].customerID = id; //give trolly (customer id) to cashier
				cashierArray[customerArray[id].cashierID].cashierLineCount--;
				ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);
			}*/
		}
	}
	/*
	/*debugPrint("acquiring cashierlock");*/
	/*AcquireLock(cashierArray[customerArray[id].cashierID].cashierLock);*/
	/*debugPrint("acquired cashierlock");*/
	/*debugPrint("about to wait on cashierlock 1");*/
	/*WaitCondition(cashierArray[customerArray[id].cashierID].cashierCV,cashierArray[customerArray[id].cashierID].cashierLock);*/ /*wait in line for cashier to call customer forward*/
	/*debugPrint("woken up on cashierlock 2");*/
	/*cashierArray[customerArray[id].cashierID].servingCustomer = 1;*/
	/*cashierArray[customerArray[id].cashierID].customerID = id; //give trolly (customer id) to cashier*/
	/*debugPrint("about to signal on cashierlock 3 - //tell cashier that they have trolly (customer id)");*/
	SignalCondition(cashierArray[customerArray[id].cashierID].cashierCV,cashierArray[customerArray[id].cashierID].cashierLock); /*tell cashier that they have trolly (customer id)*/
	
	/*debugPrint("about to wait on cashierlock 4 - //wait for cashier to ask for money");*/
	WaitCondition(cashierArray[customerArray[id].cashierID].cashierCV,cashierArray[customerArray[id].cashierID].cashierLock); /*wait for cashier to ask for money*/
	/*debugPrint("woken up and about to signal on cashierlock 5 - //tell cashier they have the money (it was included with customer id)");*/
	SignalCondition(cashierArray[customerArray[id].cashierID].cashierCV,cashierArray[customerArray[id].cashierID].cashierLock); /*tell cashier they have the money (it was included with customer id)*/
	/*debugPrint("about to wait on cashierlock 6 - //wait for cashier to say whether customer has enough");*/
	WaitCondition(cashierArray[customerArray[id].cashierID].cashierCV,cashierArray[customerArray[id].cashierID].cashierLock); /*wait for cashier to say whether customer has enough*/
	/*debugPrint("woken up on cashierlock 7 - //if the customer gave the cashier money and the cashier said it was enough");*/
	if(customerArray[id].canPay) /*if the customer gave the cashier money and the cashier said it was enough*/
	{
		/*print that cusomer paid and is waiting for receipt*/
		if(customerArray[id].privileged)
			Print("PrivilegedCustomer [%d] pays [", sizeof("PrivilegedCustomer [%d] pays ["), id*10000, -1);
		else
			Print("Customer [%d] pays [", sizeof("Customer [%d] pays ["), id*10000, -1);
		
		convertToDollarsAndCents(customerArray[id].bill);
		Print("] to Cashier [%d] and is now waiting for receipt.\n", sizeof("] to Cashier [%d] and is now waiting for receipt.\n"), customerArray[id].cashierID*10000, -1);
		
		
			/*debugPrint("about to signal on cashierlock 8 - //pay cashier");*/
		SignalCondition(cashierArray[customerArray[id].cashierID].cashierCV,cashierArray[customerArray[id].cashierID].cashierLock); /*request receipt from cashier*/
		/*debugPrint("about to wait on cashierCV, cashierlock 9 - //wait for acknowledgement of payment");*/
		WaitCondition(cashierArray[customerArray[id].cashierID].cashierCV,cashierArray[customerArray[id].cashierID].cashierLock); /*wait for receipt from cashier*/
			/*debugPrint("about to signal on cashierlock 8a - //request receipt from cashier");*/
		SignalCondition(cashierArray[customerArray[id].cashierID].cashierCV,cashierArray[customerArray[id].cashierID].cashierLock); /*request receipt from cashier*/
		/*debugPrint("about to wait on cashierCV, cashierlock 9a - //wait for receipt from cashier");*/
		WaitCondition(cashierArray[customerArray[id].cashierID].cashierCV,cashierArray[customerArray[id].cashierID].cashierLock); /*wait for receipt from cashier*/
		
		/*print leaving message*/
		if(customerArray[id].privileged)
		{
			/*AcquireLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);*/
			Print("PrivilegedCustomer [%d] got receipt from Cashier [%d] and is now leaving.\n",sizeof("PrivilegedCustomer [%d] got receipt from Cashier [%d] and is now leaving.\n"), id*10000+ customerArray[id].cashierID,-1);
			remainingCustomers--;
			/*cashierArray[customerArray[id].cashierID].servingCustomer = 0;*/
			/*debugPrint("Remaining Customers: ",remainingCustomers);*/
			/*ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);*/
		}
		else
		{
			/*AcquireLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);*/
			Print("Customer [%d] got receipt from Cashier [%d] and is now leaving.\n",sizeof("Customer [%d] got receipt from Cashier [%d] and is now leaving.\n"), id*10000+ customerArray[id].cashierID,-1);
			remainingCustomers--;
			/*cashierArray[customerArray[id].cashierID].servingCustomer = 0;*/
			/*debugPrint("Remaining Customers: ",remainingCustomers);*/
			/*ReleaseLock(cashierArray[customerArray[id].cashierID].checkOrModifyLinesLock);*/
		}
	}
	else
	{
		/*print that customer is waiting to negotiate with manager*/
		if(customerArray[id].privileged)
		{
			Print("PrivilegedCustomer [%d] cannot pay [", sizeof("PrivilegedCustomer [%d] cannot pay ["), id*10000, -1);
			convertToDollarsAndCents(customerArray[id].bill);
			PrintString("]\n", sizeof("]\n"));
			
			Print("PrivilegedCustomer [%d] is waiting for Manager for negotiations.\n",sizeof("PrivilegedCustomer [%d] is waiting for Manager for negotiations.\n"), id*10000,-1);
		}
		else
		{
			Print("Customer [%d] cannot pay [", sizeof("Customer [%d] cannot pay ["), id*10000, -1);
			convertToDollarsAndCents(customerArray[id].bill);
			PrintString("]\n", sizeof("]\n"));
			
			Print("Customer [%d] is waiting for Manager for negotiations.\n",sizeof("Customer [%d] is waiting for Manager for negotiations.\n"), id*10000,-1);
		}
		
		AcquireLock(manager.managerLock);
		customerArray[id].readyToNegotiate = 1;
		WaitCondition(manager.managerCV,manager.managerLock); /*wait for manager for negotiations*/

		/*customer removes items from cart one at a time until bill <= the money in the customer's wallet*/
		while(customerArray[id].bill > customerArray[id].money)
		{
			if(customerArray[id].trolly.itemList[0] > 0) /*if the customer has item type 0*/
			{
				/*remove 1  of item type 0 from trolly and total bill*/
				customerArray[id].trolly.itemList[0]--;
				customerArray[id].bill -= pricesOfItems[0];
				if(customerArray[id].privileged)
					Print("PrivilegedCustomer [%d] tells Manager to remove [item%d] from trolly.\n",sizeof("PrivilegedCustomer [%d] tells Manager to remove [item%d] from trolly.\n"), id*10000+ 0,-1);
				else
					Print("Customer [%d] tells Manager to remove [item%d] from trolly.\n",sizeof("Customer [%d] tells Manager to remove [item%d] from trolly.\n"), id*10000+ 0,-1);
				
				manager.itemToRemove = 0;
				SignalCondition(manager.managerCV,manager.managerLock); /*tell manager to remove item*/
				WaitCondition(manager.managerCV,manager.managerLock); /*wait for manager to remove item*/
			}
			else if(customerArray[id].trolly.itemList[1] > 0) /*if the customer has item type 1*/
			{
				/*remove 1  of item type 1 from trolly and total bill*/
				customerArray[id].trolly.itemList[1]--;
				customerArray[id].bill -= pricesOfItems[1];
				if(customerArray[id].privileged)
					Print("PrivilegedCustomer [%d] tells Manager to remove [item%d] from trolly.\n",sizeof("PrivilegedCustomer [%d] tells Manager to remove [item%d] from trolly.\n"), id*10000+ 1,-1);
				else
					Print("Customer [%d] tells Manager to remove [item%d] from trolly.\n",sizeof("Customer [%d] tells Manager to remove [item%d] from trolly.\n"), id*10000+ 1,-1);
					
				manager.itemToRemove = 1;
				SignalCondition(manager.managerCV,manager.managerLock); /*tell manager to remove item*/
				WaitCondition(manager.managerCV,manager.managerLock); /*wait for manager to remove item*/
			}
			else if(customerArray[id].trolly.itemList[2] > 0) /*if the customer has item type 2*/
			{
				/*remove 1  of item type 2 from trolly and total bill*/
				customerArray[id].trolly.itemList[2]--;
				customerArray[id].bill -= pricesOfItems[2];
				if(customerArray[id].privileged)
					Print("PrivilegedCustomer [%d] tells Manager to remove [item%d] from trolly.\n",sizeof("PrivilegedCustomer [%d] tells Manager to remove [item%d] from trolly.\n"), id*10000+ 2,-1);
				else
					Print("Customer [%d] tells Manager to remove [item%d] from trolly.\n",sizeof("Customer [%d] tells Manager to remove [item%d] from trolly.\n"), id*10000+ 2,-1);
					
				manager.itemToRemove = 2;
				SignalCondition(manager.managerCV,manager.managerLock); /*tell manager to remove item*/
				WaitCondition(manager.managerCV,manager.managerLock); /*wait for manager to remove item*/
			}
			else if(customerArray[id].trolly.itemList[3] > 0) /*if the customer has item type 3*/
			{
				/*remove 1  of item type 3 from trolly and total bill*/
				customerArray[id].trolly.itemList[3]--;
				customerArray[id].bill -= pricesOfItems[3];
				if(customerArray[id].privileged)
					Print("PrivilegedCustomer [%d] tells Manager to remove [item%d] from trolly.\n",sizeof("PrivilegedCustomer [%d] tells Manager to remove [item%d] from trolly.\n"), id*10000+ 3,-1);
				else
					Print("Customer [%d] tells Manager to remove [item%d] from trolly.\n",sizeof("Customer [%d] tells Manager to remove [item%d] from trolly.\n"), id*10000+ 3,-1);
					
				manager.itemToRemove = 3;
				SignalCondition(manager.managerCV,manager.managerLock); /*tell manager to remove item*/
				WaitCondition(manager.managerCV,manager.managerLock); /*wait for manager to remove item*/
			}
			else if(customerArray[id].trolly.itemList[4] > 0) /*if the customer has item type 4*/
			{
				/*remove 1  of item type 4 from trolly and total bill*/
				customerArray[id].trolly.itemList[4]--;
				customerArray[id].bill -= pricesOfItems[4];
				if(customerArray[id].privileged)
					Print("PrivilegedCustomer [%d] tells Manager to remove [item%d] from trolly.\n",sizeof("PrivilegedCustomer [%d] tells Manager to remove [item%d] from trolly.\n"), id*10000+ 4,-1);
				else
					Print("Customer [%d] tells Manager to remove [item%d] from trolly.\n",sizeof("Customer [%d] tells Manager to remove [item%d] from trolly.\n"), id*10000+ 4,-1);
					
				manager.itemToRemove = 4;
				SignalCondition(manager.managerCV,manager.managerLock); /*tell manager to remove item*/
				WaitCondition(manager.managerCV,manager.managerLock); /*wait for manager to remove item*/
			}
		}
		
		manager.itemToRemove = -2; /*done removing items*/
		
		/*print that the customer has removed items and is waiting for manager to give the receeipt*/
		if(customerArray[id].privileged)
			Print("PrivilegedCustomer [%d] pays [", sizeof("PrivilegedCustomer [%d] pays ["), id*10000, -1);
		else
			Print("Customer [%d] pays [", sizeof("Customer [%d] pays ["), id*10000, -1);
			
		convertToDollarsAndCents(customerArray[id].bill);
		PrintString("] to Manager after removing items and is waiting for receipt from Manager.\n", sizeof("] to Manager after removing items and is waiting for receipt from Manager.\n"));
			
			
		SignalCondition(manager.managerCV,manager.managerLock); /*tell manager you're done removing items and pay*/
		WaitCondition(manager.managerCV,manager.managerLock); /*wait for receipt*/
		
		/*print that customer is leaving*/
		Print("Customer [%d] got receipt from Manager and is now leaving.\n",sizeof("Customer [%d] got receipt from Manager and is now leaving.\n"), id*10000,-1);
		remainingCustomers--;
		/*cashierArray[customerArray[id].cashierID].servingCustomer = 0;*/
		/*debugPrint("Remaining Customers: ",remainingCustomers);*/
		ReleaseLock(manager.managerLock);
	}
	/*cashierArray[customerArray[id].cashierID].servingCustomer = 0;*/
	/*debugPrint("releasing cashierlock");*/
	ReleaseLock(cashierArray[customerArray[id].cashierID].cashierLock);
	/*if (remainingCustomers == 0)*/
	/*	printEndOfSimulationOutputs();*/
	Exit(0);
}
/*=================================================//*/
/*---------------(END) CUSTOMER--------------------//*/
/*=================================================//*/

/*=================================================//*/
/*-------------------CASHIER-----------------------//*/
/*=================================================//*/
void CashierSetup(int id){ /*called when initializing a new Cashier*/
	cashierArray[id].identifier = id;
	cashierArray[id].cashierLineCount = 0;
	cashierArray[id].cashierPrivilegedLineCount = 0;
	cashierArray[id].customerID = -1;
	cashierArray[id].servingCustomer = 0;
	cashierArray[id].goOnBreak = 0;
	cashierArray[id].onBreak = 0;
	
	cashierArray[id].checkOrModifyLinesLock = CreateLock("Check or Modify Lines", sizeof("Check or Modify Lines"));
	cashierArray[id].cashierLock = CreateLock("Cashier Lock", sizeof("Cashier Lock"));
	cashierArray[id].cashierCV = CreateCondition("Cashier CV", sizeof("Cashier CV"));
	cashierArray[id].cashierLineLock = CreateLock("Cashier Line Lock", sizeof("Cashier Line Lock"));
	cashierArray[id].cashierLineCV = CreateCondition("Cashier Line CV", sizeof("Cashier Line CV"));
	cashierArray[id].cashierPrivilegedLineLock = CreateLock("Cashier Privileged Line Lock", sizeof("Cashier Privileged Line Lock"));
	cashierArray[id].cashierPrivilegedLineCV = CreateCondition("Cashier Privileged Line CV", sizeof("Cashier Privileged Line CV"));
}

void CheckoutCounterSetup(int id){ /*called when initializing a new CheckoutCounter*/
	checkoutCounterArray[id].identifier = id;
	checkoutCounterArray[id].moneyInDrawer = 0;
	checkoutCounterArray[id].totalCounterSales = 0;
	checkoutCounterArray[id].drawerLock = CreateLock("Drawer Lock", sizeof("Drawer Lock"));
}

void CashierFunction(){
	int i, j, id, bill;
	
	AcquireLock(idLock);
	id = cashierIDCount;
	cashierIDCount++;
	ReleaseLock(idLock);
	
	while(1)
	{
		/*Get line locks*/
		/*debugPrint("Cashier");*/
		AcquireLock(cashierArray[id].cashierLock);
		/*debugPrint("acquiring cashierlineslock");*/
		AcquireLock(cashierLinesLock);
		/*debugPrint("acquired cashierlineslock");*/
		
		/*debugPrint("acquiring cashierpriviligedLINElock");*/
		AcquireLock(cashierArray[id].cashierPrivilegedLineLock);
		/*debugPrint("privileged cashierLINElock");*/
		/*debugPrint("acquiring cashierLINElock");*/
		AcquireLock(cashierArray[id].cashierLineLock);
		/*debugPrint("acquired cashierLINElock");*/
		/*AcquireLock(cashierArray[id].cashierLock);*/
		/*debugPrint("has ALL the locks");*/
		AcquireLock(cashierArray[id].checkOrModifyLinesLock);
		if (/*cashierArray[id].goOnBreak ||*/ cashierArray[id].onBreak)
		{
			/*if (cashierArray[id].onBreak)*/
			/*{*/
				Print("Cashier [%d] was called from break by Manager to work.\n",sizeof("Cashier [%d] was called from break by Manager to work.\n"), id*10000,-1);
				cashierArray[id].goOnBreak = 0;
				cashierArray[id].onBreak = 0;
			/*}*/
		}
		/*AcquireLock(cashierArray[id].checkOrModifyLinesLock);*/
		cashierArray[id].servingCustomer = 0;
		cashierArray[id].customerID = -1;
		if(cashierArray[id].cashierPrivilegedLineCount > 0)
		{
			ReleaseLock(cashierArray[id].checkOrModifyLinesLock);
			/*debugPrint("signaling privcustomer, cashierCV, cashierLock");*/
			/*Call up next privileged customer*/
			/*debugPrint("signaling cashierprivilegedLINElock");*/
			SignalCondition(cashierArray[id].cashierPrivilegedLineCV,cashierArray[id].cashierPrivilegedLineLock);
			/*cashierArray[id].cashierPrivilegedLineCount--;*/
		}
		else if(cashierArray[id].cashierLineCount > 0)
		{
			ReleaseLock(cashierArray[id].checkOrModifyLinesLock);
			/*debugPrint("signaling customer, cashierCV, cashierLock");*/
			/*Call up next regular customer*/
			
			/*debugPrint("signaling cashierLINElock");*/
			SignalCondition(cashierArray[id].cashierLineCV,cashierArray[id].cashierLineLock);
			/*cashierArray[id].cashierLineCount--;*/
		}
		else
		{
			ReleaseLock(cashierArray[id].checkOrModifyLinesLock);
			/*debugPrint("Signaling cashierCV, cashierLock");*/
			SignalCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock);
		}
		
		
		/*debugPrint("releasing cashierprivilegedLINElock");*/
		ReleaseLock(cashierArray[id].cashierPrivilegedLineLock);
		/*debugPrint("released cashierprivilegedLINElock");*/
		/*debugPrint("releasing cashierLINElock");*/
		ReleaseLock(cashierArray[id].cashierLineLock);
		/*debugPrint("released cashierLINElock");*/
		/*debugPrint("releasing cashierlineslock");*/
		ReleaseLock(cashierLinesLock);
		/*debugPrint("released cashierlineslock");*/
		
		/*Wait for customer to give trolly (customer ID) to cashier*/
		/*debugPrint("waiting on cashierCV, cashierLock");*/
		WaitCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock);
		AcquireLock(cashierArray[id].checkOrModifyLinesLock);
		if(cashierArray[id].servingCustomer == 1)
		{
			ReleaseLock(cashierArray[id].checkOrModifyLinesLock);
			/*Add up items in trolly*/
			bill = 0;
			for(i = 0; i < NUM_DEPARTMENTS; i++)
			{
				if(customerArray[cashierArray[id].customerID].privileged)
				{
					for(j = 0; j < customerArray[cashierArray[id].customerID].trolly.itemList[i]; j++)
					{
						/*print that cashier got item*/
						Print("Cashier [%d] got [item%d] from trolly of PrivilegedCustomer [%d].\n",sizeof("Cashier [%d] got [item%d] from trolly of PrivilegedCustomer [%d].\n"), id*10000+ i, cashierArray[id].customerID*10000);
					}
				}
				else
				{
					for(j = 0; j < customerArray[cashierArray[id].customerID].trolly.itemList[i]; j++)
					{
						/*print that cashier got item*/
						Print("Cashier [%d] got [item%d] from trolly of Customer [%d].\n",sizeof("Cashier [%d] got [item%d] from trolly of Customer [%d].\n"), id*10000+ i, cashierArray[id].customerID*10000);
					}
				}
				
				/*add items of type i from customer's trolly to customer's bill*/
				bill += customerArray[cashierArray[id].customerID].trolly.itemList[i] * pricesOfItems[i]; 
			}
			
			/*Give customer their bill*/
			AcquireLock(cashierArray[id].cashierLock);
			customerArray[cashierArray[id].customerID].bill = bill;
			
			/* Tell customer that they have the bill*/
			if(customerArray[cashierArray[id].customerID].privileged)
				Print("Cashier [%d] tells PrivilegedCustomer [%d] total cost is $[", sizeof("Cashier [%d] tells PrivilegedCustomer [%d] total cost is $["), id*10000+cashierArray[id].customerID, -1);
			else
				Print("Cashier [%d] tells Customer [%d] total cost is $[", sizeof("Cashier [%d] tells Customer [%d] total cost is $["), id*10000+cashierArray[id].customerID, -1);
			
			convertToDollarsAndCents(bill);
			PrintString("].\n", sizeof("].\n"));
			
			
			
			SignalCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock);
			
			/* Wait for customer to pay*/
			/*debugPrint("waiting on cashierCV, cashierLock 2");*/
			WaitCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock);
			
			if(customerArray[cashierArray[id].customerID].money < bill) /*if the customer can't pay*/
			{	
				/*let the customer know they can't pay*/
				customerArray[cashierArray[id].customerID].canPay = 0;
				
				/*tell customer to wait for manager*/
				if(customerArray[cashierArray[id].customerID].privileged)
					Print("Cashier [%d] asks PrivilegedCustomer [%d] to wait for Manager.\n",sizeof("Cashier [%d] asks PrivilegedCustomer [%d] to wait for Manager.\n"), id*10000+ cashierArray[id].customerID,-1);
				else
					Print("Cashier [%d] asks Customer [%d] to wait for Manager.\n",sizeof("Cashier [%d] asks Customer [%d] to wait for Manager.\n"), id*10000+ cashierArray[id].customerID,-1);
				SignalCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock);
				
				/*Give manager cashier/counter ID so he can find the problem*/
				/*debugPrint("A %d", cashierArray[id].customerID);*/
				AcquireLock(manager.managerLock);
				/*debugPrint("B %d", cashierArray[id].customerID);*/
				while(manager.currentCashierID != id) /*while the manager is not helping the customer at this counter*/
				{
					/*debugPrint("C");*/
					if(manager.currentCashierID == -1) /*if the manager isn't helping anyone*/
					{
						/*debugPrint("D");*/
						manager.currentCashierID = id; /*tell the manager to help the customer at this counter*/
					}
					else
					{
						/*debugPrint("E");*/
						WaitCondition(manager.managerCashierLineCV,manager.managerLock); /*wait for manager to say he's done helping the previous customer*/
						/*debugPrint("F");*/
					}
					/*debugPrint("G");*/
				}
				/*debugPrint("H");*/
				
				/*Tells manager that customer does not have enough money*/
				if(customerArray[cashierArray[id].customerID].privileged)
					Print("Cashier [%d] informs the Manager that PrivilegedCustomer [%d] does not have enough money.\n",sizeof("Cashier [%d] informs the Manager that PrivilegedCustomer [%d] does not have enough money.\n"), id*10000+ cashierArray[id].customerID,-1);
				else
					Print("Cashier [%d] informs the Manager that Customer [%d] does not have enough money.\n",sizeof("Cashier [%d] informs the Manager that Customer [%d] does not have enough money.\n"), id*10000+ cashierArray[id].customerID,-1);
				
				/*Waits for manager to finish helping customer and give cashier the final bill (so the cashier can add the money to the drawer)*/
				/*debugPrint("manager's current cashier ID %d", manager.currentCashierID);*/
				ReleaseLock(cashierArray[id].cashierLock);
				/*debugPrint("Cashier waiting on managerCashierHelpCV, managerLock");*/
				WaitCondition(manager.managerCashierHelpCV,manager.managerLock);
				
				bill = customerArray[cashierArray[id].customerID].bill; /*customer's final bill*/
				ReleaseLock(manager.managerLock);
			}
			else
			{			
				/*Take the appropriate amount of money from the customer (give them their change)*/
				/*customerArray[cashierArray[id].customerID].money -= bill;*/
				
				/* Tell customer they can leave*/
				if(customerArray[cashierArray[id].customerID].privileged)
				{
					/*cashierArray[id].cashierPrivilegedLineCount--;*/
					/*debugPrint("privlinecount %d",cashierArray[id].cashierPrivilegedLineCount);*/
					/*debugPrint("signaling on cashierCV, cashierLock 2a - //tell customer that he had enough money");*/
					SignalCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock); /*tell customer the payment was successful*/
					/*debugPrint("waiting on cashierCV, cashierLock 3a - //wait for customer to pay");*/
					WaitCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock); /*wait for customer to ask for receipt*/
					/*Take the appropriate amount of money from the customer (give them their change)*/
					customerArray[cashierArray[id].customerID].money -= bill;
					
					Print("Cashier [%d] got money $[", sizeof("Cashier [%d] got money $["), id*10000, -1);
					convertToDollarsAndCents(bill);
					Print("] from PrivilegedCustomer [%d].\n", sizeof("] from PrivilegedCustomer [%d].\n"), cashierArray[id].customerID*10000, -1);
					
					/*debugPrint("signaling on cashierCV, cashierLock 4a - //tell customer the payment was successful");*/
					SignalCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock); /*tell customer the payment was successful*/
					/*debugPrint("waiting on cashierCV, cashierLock 5a - //wait for customer to ask for receipt");*/
					WaitCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock); /*wait for customer to ask for receipt*/
					Print("Cashier [%d] gave the receipt to PrivilegedCustomer [%d] and tells him to leave.\n",sizeof("Cashier [%d] gave the receipt to PrivilegedCustomer [%d] and tells him to leave.\n"), id*10000+ cashierArray[id].customerID,-1);
				}
				else
				{
					/*cashierArray[id].cashierLineCount--;*/
					/*debugPrint("linecount %d",cashierArray[id].cashierLineCount);*/
					/*debugPrint("signaling on cashierCV, cashierLock 2b - //tell customer that he had enough money");*/
					SignalCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock); /*tell customer the payment was successful*/
					/*debugPrint("waiting on cashierCV, cashierLock 3b - //wait for customer to pay");*/
					WaitCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock); /*wait for customer to ask for receipt*/
					/*Take the appropriate amount of money from the customer (give them their change)*/
					customerArray[cashierArray[id].customerID].money -= bill;
					
					Print("Cashier [%d] got money $[", sizeof("Cashier [%d] got money $["), id*10000, -1);
					convertToDollarsAndCents(bill);
					Print("] from Customer [%d].\n", sizeof("] from Customer [%d].\n"), cashierArray[id].customerID*10000, -1);
					
					/*debugPrint("signaling on cashierCV, cashierLock 4b - //tell customer the payment was successful");*/
					SignalCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock); /*tell customer the payment was successful*/
					/*debugPrint("waiting on cashierCV, cashierLock 5b - //wait for customer to ask for receipt");*/
					WaitCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock); /*wait for customer to ask for receipt*/
					Print("Cashier [%d] gave the receipt to Customer [%d] and tells him to leave.\n",sizeof("Cashier [%d] gave the receipt to Customer [%d] and tells him to leave.\n"), id*10000+ cashierArray[id].customerID,-1);
					/*/*debugPrint("linecount %d",cashierArray[id].cashierLineCount);*/
					/*debugPrint("signaling on cashierCV, cashierLock 4 - //tell customer the payment was successful");*/
					/*SignalCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock);*/ /*tell customer the payment was successful*/
					/*debugPrint("waiting on cashierCV, cashierLock 5 - //wait for customer to ask for receipt");*/
					/*WaitCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock);*/ /*wait for customer to ask for receipt*/
				}
				
				/*debugPrint("privlinecount %d",cashierArray[id].cashierPrivilegedLineCount);*/
				/*debugPrint("linecount %d",cashierArray[id].cashierLineCount);*/
				
				/*debugPrint("signaling on cashierCV, cashierLock 6 - //tell customer to leave");*/
				SignalCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock);
			}
			
			/*Add the customer's money to drawer*/
			AcquireLock(checkoutCounterArray[id].drawerLock);
			checkoutCounterArray[id].moneyInDrawer += bill;
			checkoutCounterArray[id].totalCounterSales += bill;
			ReleaseLock(checkoutCounterArray[id].drawerLock);
			
			/*put back trolly*/
			AcquireLock(trollyLineLock);
			numTrolly++;
			SignalCondition(trollyLineCV,trollyLineLock);
			ReleaseLock(trollyLineLock);
		}
		else
		{
			ReleaseLock(cashierArray[id].checkOrModifyLinesLock);
		}
		if(cashierArray[id].goOnBreak)
		{
			cashierArray[id].onBreak = 1;
			
			AcquireLock(cashierArray[id].cashierPrivilegedLineLock);
			AcquireLock(cashierArray[id].cashierLineLock);
			AcquireLock(cashierArray[id].checkOrModifyLinesLock);
			/*debugPrint("going on break, broadcast to lines");*/
			BroadcastCondition(cashierArray[id].cashierPrivilegedLineCV,cashierArray[id].cashierPrivilegedLineLock);
			cashierArray[id].cashierPrivilegedLineCount = 0;
			BroadcastCondition(cashierArray[id].cashierLineCV,cashierArray[id].cashierLineLock);
			cashierArray[id].cashierLineCount = 0;
			
			ReleaseLock(cashierArray[id].cashierPrivilegedLineLock);
			ReleaseLock(cashierArray[id].cashierLineLock);
			ReleaseLock(cashierArray[id].checkOrModifyLinesLock);
			
			/*Go on break until signaled by manager*/
			Print("Cashier [%d] is going on break.\n",sizeof("Cashier [%d] is going on break.\n"), id*10000,-1);
			/*debugPrint("waiting on cashierCV, cashierLock 4");*/
			WaitCondition(cashierArray[id].cashierCV,cashierArray[id].cashierLock);
			
			/*Return from break*/
			/*Print("Cashier [%d] was called from break by Manager to work.\n",sizeof("Cashier [%d] was called from break by Manager to work.\n"), id*10000,-1);*/
			/*cashierArray[id].goOnBreak = 0;*/
			/*cashierArray[id].onBreak = 0;*/
		}
		/*debugPrint("releasing cashierlock");*/
		ReleaseLock(cashierArray[id].cashierLock);
		/*debugPrint("released cashierlock");*/
	}
	Exit(0);
}
/*=================================================//*/
/*----------------(END) CASHIER--------------------//*/
/*=================================================//*/


/*=================================================//*/
/*----------------GOODS LOADER---------------------//*/
/*=================================================//*/
/*Setup function for the goodsloader: initializes variables in goodsloader*/
void GoodsLoaderSetup(int id){
	goodsLoaderArray[id].identifier = id;
	/*Print("This is goodsloader %d\n",sizeof("This is goodsloader %d\n"), g.identifier*10000,-1);*/
	
	/*initializes the condition variable for talking to the goodsloader*/
	goodsLoaderArray[id].goodsLoaderCV = CreateCondition("GoodsLoader CV", sizeof("GoodsLoader CV"));
}

/*This function is called when a salesman is complaining about an out of stock item.
	Wakes up a goods loader by checking the goodsLoaderStatus array
	Print("GoodsLoader [%d] is informed by DepartmentSalesman [%d] of Department [%d] to restock [item%d].\n", goodsLoaderID,sizeof("GoodsLoader [%d] is informed by DepartmentSalesman [%d] of Department [%d] to restock [item%d].\n", goodsLoaderID), salesmanID*10000+ departmentID, itemID*10000);
	tell the goodsloader to go restock, resume tasks.
*/
/*void GoodsLoaderComplainingSalesman(int goodsID, int departID, int salesID)
{
	int goodsLoaderID, departmentID, salesmanID, itemID;
	goodsLoaderID = goodsID;
	departmentID = departID;
	itemID = departID;
	salesmanID = salesID;
	Print("GoodsLoader [%d] is informed by DepartmentSalesman [%d] of Department [%d] to restock [item%d].\n", goodsLoaderID,sizeof("GoodsLoader [%d] is informed by DepartmentSalesman [%d] of Department [%d] to restock [item%d].\n", goodsLoaderID), salesmanID*10000+ departmentID, itemID*10000);
	goodsLoaderArray[goodsLoaderID].departmentToRestock = departmentID;
	goodsLoaderArray[goodsLoaderID].itemToRestock = itemID;
	goodsLoaderArray[goodsLoaderID].salesmanToNotifyAfterRestock = salesmanID;
}*/
void GoodsLoaderFunction(){
	int i, j, walkToDepartmentProgress, goodsLoaderID, timeToWalkToDepartment, waitInLine;
	
	/*All goods loader code goes here*/
	AcquireLock(idLock);
	goodsLoaderID = goodsLoaderIDCount;
	goodsLoaderIDCount++;
	ReleaseLock(idLock);
	
	while (1)
	{
			/*debugPrint("0 - about to acquire SLRL, status: %d",goodsLoaderStatus[goodsLoaderID]);*/
		/*acquire salesloaderrestock lock and CV, and sleep.*/
		AcquireLock(salesLoaderRestockLock);
		/*debugPrint("acquired SLRL");*/
		/*Idle/do nothing*/
		
			/*debugPrint("1 status: %d",goodsLoaderStatus[goodsLoaderID]);*/
		if (goodsLoaderStatus[goodsLoaderID] == 0 || goodsLoaderStatus[goodsLoaderID] == 6)
		{
			for(i = 0; i < NUM_DEPARTMENTS; i++)
			{
				if (departmentsToRestock[i] != -1)
				{
					goodsLoaderArray[goodsLoaderID].departmentToRestock = -1;
					goodsLoaderArray[goodsLoaderID].itemToRestock = -1;
					goodsLoaderArray[goodsLoaderID].salesmanToNotifyAfterRestock = -1;
					whichDepartmentToRestock[goodsLoaderID] = i;
					salesmanOrderedRestock[goodsLoaderID] = departmentsToRestock[i];
					goodsLoaderStatus[goodsLoaderID] = 1;
					/*debugPrint("\n\n\n\n\n\n****SECONDARY GOODSLOADER CALL USED*******\n\n\n\n\n");*/
					Print("DepartmentSalesman [%d] informs the GoodsLoader [%d] that [item%d] is out of stock.\n",sizeof("DepartmentSalesman [%d] informs the GoodsLoader [%d] that [item%d] is out of stock.\n"), salesmanOrderedRestock[goodsLoaderID]*10000+ goodsLoaderID, whichDepartmentToRestock[goodsLoaderID]*10000);
					departmentsToRestock[i] = -1;
					break;
				}
			}
			if(goodsLoaderStatus[goodsLoaderID] != 1)
			{
				goodsLoaderStatus[goodsLoaderID] = 0;
				/*debugPrint("2 status: %d",goodsLoaderStatus[goodsLoaderID]);*/
				Print("GoodsLoader [%d] is waiting for orders to restock.\n",sizeof("GoodsLoader [%d] is waiting for orders to restock.\n"), goodsLoaderID*10000,-1);
				goodsLoaderArray[goodsLoaderID].departmentToRestock = -1;
				goodsLoaderArray[goodsLoaderID].itemToRestock = -1;
				goodsLoaderArray[goodsLoaderID].salesmanToNotifyAfterRestock = -1;
				/*debugPrint("about to wait on goodsLoaderCV, salesLoaderRestockLock");*/
				WaitCondition(goodsLoaderArray[goodsLoaderID].goodsLoaderCV,salesLoaderRestockLock);
				/*debugPrint("woke up from goodsLoaderCV, salesLoaderRestockLock");*/
			}
		}
		/*ReleaseLock(salesLoaderRestockLock);*/
		if (goodsLoaderStatus[goodsLoaderID] != 0)
		{
			/*debugPrint("3 status: %d",goodsLoaderStatus[goodsLoaderID]);*/
			/*GoodsLoader is told by a salesman to restock an item in a department.*/
			if (goodsLoaderArray[goodsLoaderID].salesmanToNotifyAfterRestock == -1 && goodsLoaderStatus[goodsLoaderID] == 1)
			{
				goodsLoaderArray[goodsLoaderID].departmentToRestock = whichDepartmentToRestock[goodsLoaderID];
				goodsLoaderArray[goodsLoaderID].itemToRestock = whichDepartmentToRestock[goodsLoaderID];
				goodsLoaderArray[goodsLoaderID].salesmanToNotifyAfterRestock = salesmanOrderedRestock[goodsLoaderID];
				Print("GoodsLoader [%d] is informed by DepartmentSalesman [%d] of Department [%d] to restock [item%d].\n",sizeof("GoodsLoader [%d] is informed by DepartmentSalesman [%d] of Department [%d] to restock [item%d].\n"), goodsLoaderID*10000+ goodsLoaderArray[goodsLoaderID].salesmanToNotifyAfterRestock, goodsLoaderArray[goodsLoaderID].departmentToRestock*10000+ goodsLoaderArray[goodsLoaderID].itemToRestock);
			}/*debugPrint("1aa");*/
			if (goodsLoaderStatus[goodsLoaderID] == 1)
			{/*debugPrint("1a");*/
				/*GoodsLoader attempts to acquire lock for StockRoom, as only one GoodsLoader may be in the StockRoom at a time.*/
				AcquireLock(stockRoomLock);
				/*If there is already a GoodsLoader in the StockRoom, wait for that GoodsLoader to leave.*/
				if (goodsLoaderInStockRoom != -1)
					Print("GoodsLoader [%d] is waiting for GoodsLoader [%d] to leave the StockRoom.\n",sizeof("GoodsLoader [%d] is waiting for GoodsLoader [%d] to leave the StockRoom.\n"), goodsLoaderID*10000+goodsLoaderInStockRoom,-1);
				else
				{
					goodsLoaderStatus[goodsLoaderID]=2;
					goodsLoaderInStockRoom=goodsLoaderID;
				}
				ReleaseLock(stockRoomLock);
			}/*debugPrint("1c");*/
			
			/*Once GoodsLoader acquires lock for StockRoom, the GoodsLoader retrieves 10 of the requested item.*/
			if (goodsLoaderStatus[goodsLoaderID] == 2)
			{
				/*Once GoodsLoader acquires lock for StockRoom, the GoodsLoader retrieves 10 of the requested item.*/
				goodsLoaderArray[goodsLoaderID].numberOfItems=10;
				Print("GoodsLoader [%d] is in the StockRoom and got [item%d].\n",sizeof("GoodsLoader [%d] is in the StockRoom and got [item%d].\n"), goodsLoaderID*10000+ goodsLoaderArray[goodsLoaderID].itemToRestock,-1);
				
				AcquireLock(stockRoomLock);
				/*GoodsLoader leaves the StockRoom and releases its lock.*/
				goodsLoaderStatus[goodsLoaderID]=3;
				goodsLoaderInStockRoom=-1;
				Print("GoodsLoader [%d] leaves StockRoom.\n",sizeof("GoodsLoader [%d] leaves StockRoom.\n"), goodsLoaderID*10000,-1);
				ReleaseLock(stockRoomLock);
			}/*debugPrint("2c");*/
			/*GoodsLoader walks to the department that needs restocking (this takes time, which is simulated by a random number [between 20 and 40] of 'Yield()' statements.*/
			if (goodsLoaderStatus[goodsLoaderID] == 3)
			{
				timeToWalkToDepartment = randInt(20,40);
				for (walkToDepartmentProgress=0; walkToDepartmentProgress < timeToWalkToDepartment; walkToDepartmentProgress++)
					Yield();
				goodsLoaderStatus[goodsLoaderID] = 4;
			}/*debugPrint("3c");*/
			/*GoodsLoader attempts to acquire lock of the department that needs restocking.*/
			if (goodsLoaderStatus[goodsLoaderID] == 4)
			{
				AcquireLock(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].shelfLock);
				/*Once the GoodsLoader has the lock of the department that needs restocking, the GoodsLoader restocks the items in that department. */
				departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].numberOfItems += goodsLoaderArray[goodsLoaderID].numberOfItems;
				goodsLoaderArray[goodsLoaderID].numberOfItems = 0;
				Print("GoodsLoader [%d] has restocked [item%d] in Department [%d].\n",sizeof("GoodsLoader [%d] has restocked [item%d] in Department [%d].\n"), goodsLoaderID*10000+ goodsLoaderArray[goodsLoaderID].itemToRestock, goodsLoaderArray[goodsLoaderID].departmentToRestock*10000);
				/*GoodsLoader releases the lock of the department that needed restocking.*/
				ReleaseLock(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].shelfLock);
				goodsLoaderStatus[goodsLoaderID] = 5;
			}/*debugPrint("4c");*/
			/*debugPrint("attempting to talk to salesman");*/
			/*GoodsLoader attempts to acquire the lock to talk to the salesman to notify the salesman that restocking is complete.*/
			AcquireLock(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].goodsLoaderWaitingForSalesLock);
			/*debugPrint("about to release salesLoaderRestockLock");*/
			ReleaseLock(salesLoaderRestockLock);
			/*debugPrint("relased salesLoaderRestockLock, got the line lock for salesman(did we?)");*/
			/*Once GoodsLoader acquires that lock, GoodsLoader notifies the salesman that restocking is complete.*/
			waitInLine = 1;
			/*departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].goodsLoaderWaitingLineCount++;*/
			/*	/*debugPrint("brings goodsLoaderWaitingLineCount up to %d and waits on goodsloaderwaitingforsalesCV, goodsloaderwaitingforsaleslock",departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].goodsLoaderWaitingLineCount);*/
			/*	/*debugPrint("(salesman status is %d)",departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].salesStatusArray[0]);*/
			/*WaitCondition(	departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].goodsLoaderWaitingForSalesCV,departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].goodsLoaderWaitingForSalesLock);*/
			/*	/*debugPrint("woke up from goodsLoaderwaitingforsalesCV, goodsLoaderwaitingforsaleslock");*/
			for (j = 0; j < NUM_SALESMAN; j++){
				/*debugPrint("ACQUIRING SALESMAN LOCK");*/
				AcquireLock(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanLock);
				/*debugPrint("ACQUIRED SALESMAN LOCK");*/
				/*debugPrint("goods loader checking salesman status: %d", departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].salesStatusArray[j]);*/
				if(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].salesStatusArray[j] == 0 && departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].goodsLoaderWaitingLineCount == 0 && departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].goOnBreak == 0 && departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].whomITalkTo[j]==-1)
				{/*debugPrint("did not have to wait in line");*/
					waitInLine = 0;
					
					/*/*debugPrint("ACQUIRING SALESMAN LOCK");*/
					/*AcquireLock(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanLock);*/
					/*/*debugPrint("ACQUIRED SALESMAN LOCK");*/
				
					departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].salesStatusArray[j] = 1;
					departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].salesLoaderIdentifier[j] = goodsLoaderID;
					departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].whomITalkTo[j] = 2;
					ReleaseLock(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].goodsLoaderWaitingForSalesLock);
					SignalCondition(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanCV,departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanLock);
					/*debugPrint("GOING TO SLEEP");*/
					WaitCondition(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanCV,departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanLock);
					/*debugPrint("WAKING UP");*/
					SignalCondition(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanCV,departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanLock);
					ReleaseLock(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanLock);
					goodsLoaderStatus[goodsLoaderID] = 6;
					break;
				}
				else 
				{
					/*debugPrint("nope, salesman %d status: %d",j,departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].salesStatusArray[j]);*/
					/*debugPrint("and, salesman %d whomITalkTo: %d",j,departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].whomITalkTo[j]);*/
					ReleaseLock(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanLock);
				}
			}
			if(waitInLine)
			{/*debugPrint("is waiting in line");*/
				for (j = 0; j < NUM_SALESMAN; j++)
				{
					AcquireLock(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanLock);
				}
				departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].goodsLoaderWaitingLineCount++;
				/*debugPrint("brings goodsLoaderWaitingLineCount up to %d and waits on goodsloaderwaitingforsalesCV, goodsloaderwaitingforsaleslock",departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].goodsLoaderWaitingLineCount);*/
				/*/*debugPrint("(salesman status is %d)",departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].salesStatusArray[0]);*/
				for (j = 0; j < NUM_SALESMAN; j++)
				{
					ReleaseLock(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanLock);
				}
				WaitCondition(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].goodsLoaderWaitingForSalesCV,departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].goodsLoaderWaitingForSalesLock);
				/*debugPrint("woke up from goodsLoaderwaitingforsalesCV, goodsLoaderwaitingforsaleslock");*/
				for (j = 0; j < NUM_SALESMAN; j++){
					AcquireLock(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanLock);
					/*debugPrint("(salesman status is %d)",departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].salesStatusArray[0]);*/
					if(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].salesStatusArray[j] == 3 && departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].goOnBreak == 0 && departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].whomITalkTo[j]==-1)
					{/*debugPrint("is talking to salesman");*/
						/*AcquireLock(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanLock);*/
						
						departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].salesStatusArray[j] = 1;
						departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].salesLoaderIdentifier[j] = goodsLoaderID;
						departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].whomITalkTo[j] = 2;

						ReleaseLock(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].goodsLoaderWaitingForSalesLock);
						SignalCondition(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanCV,departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanLock);
						WaitCondition(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanCV,departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanLock);
						SignalCondition(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanCV,departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanLock);
						ReleaseLock(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanLock);
						goodsLoaderStatus[goodsLoaderID] = 6;
						break;
					}
					else
					{
						/*debugPrint("nope, salesman %d status: %d",j,departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].salesStatusArray[j]);*/
						/*debugPrint("and, salesman %d whomITalkTo: %d",j,departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].whomITalkTo[j]);*/
						ReleaseLock(departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[j].salesmanLock);
					}
				}
			}
			/*departmentArray[goodsLoaderArray[goodsLoaderID].departmentToRestock].listOfSalesman[goodsLoaderArray[goodsLoaderID].salesmanToNotifyAfterRestock].*/
			/*SalesmanLoaderRestock(goodsLoaderArray[goodsLoaderID].departmentToRestock, goodsLoaderArray[goodsLoaderID].salesmanToNotifyAfterRestock, goodsLoaderID);*/
			/*GoodsLoader returns to idle OR checks other departments to see if they are out of stock and restocks them? (might cause trouble if another GoodsLoader is already doing so)*/
		}/*end else (if not idle)*/
	}/*end while (1)*/
	Exit(0);
}
/*=================================================//*/
/*--------------(END) GOODS LOADER-----------------//*/
/*=================================================//*/

/*=================================================//*/
/*-------------------SALESMAN----------------------//*/
/*=================================================//*/
/*Setup function for the salesman: initializes variables in salesman*/
void SalesmanSetup(int id, int departmentNum){
	departmentArray[departmentNum].listOfSalesman[id].identifier = id;
	departmentArray[departmentNum].listOfSalesman[id].departmentNumber = departmentNum;
	departmentArray[departmentNum].listOfSalesman[id].goOnBreak = 0;
	/*Print("This is salesman %d\n",sizeof("This is salesman %d\n"), s.identifier*10000,-1);*/
	/*Print("from department %d\n\n",sizeof("from department %d\n\n"), s.departmentNumber*10000,-1);*/
	
	/*initializes the lock for talking to the salesman*/
	departmentArray[departmentNum].listOfSalesman[id].salesmanLock = CreateLock("Salesman Lock", sizeof("Salesman Lock"));
	
	/*initializes the condition variable for talking to the salesman*/
	departmentArray[departmentNum].listOfSalesman[id].salesmanCV = CreateCondition("Salesman CV", sizeof("Salesman CV"));
	
	/*initializes the condition variable for salesman going on break*/
	departmentArray[departmentNum].listOfSalesman[id].salesmanOnBreakCV = CreateCondition("Salesman On Break CV", sizeof("Salesman On Break CV"));
}

/*This function is called when a customer is to be greeted
it signals the customer after printing the output statement
*/
void SalesmanGreetingCustomer(int departID, int salesID, int custID)
{
	int departmentID, salesmanID, customerID;
	departmentID = departID;
	salesmanID = salesID;
	customerID = custID;
	if(customerArray[customerID].privileged)
	{
		Print("DepartmentSalesman [%d] welcomes PrivilegeCustomer [%d] to Department [%d].\n",sizeof("DepartmentSalesman [%d] welcomes PrivilegeCustomer [%d] to Department [%d].\n"), salesmanID*10000+ customerID, departmentID*10000);
	}
	else
	{
		Print("DepartmentSalesman [%d] welcomes Customer [%d] to Department [%d].\n",sizeof("DepartmentSalesman [%d] welcomes Customer [%d] to Department [%d].\n"), salesmanID*10000+ customerID, departmentID*10000);
	}
	/*signal the customer to wake up and continue shopping.*/
	SignalCondition(departmentArray[departmentID].listOfSalesman[salesmanID].salesmanCV,departmentArray[departmentID].listOfSalesman[salesmanID].salesmanLock);
	departmentArray[departmentID].whomITalkTo[salesmanID] = -1;
}

/*This function is called when a customer is complaining about an out of stock item.
	Wakes up a goods loader by checking the goodsLoaderStatus array
	Print("DepartmentSalesman [%d] informs the GoodsLoader [%d] that [item%d] is out of stock.\n",sizeof("DepartmentSalesman [%d] informs the GoodsLoader [%d] that [item%d] is out of stock.\n"), salesmanID*10000+ loaderID, departmentID*10000);
	tell the goodsloader to go restock, resume tasks.
*/
void SalesmanComplainingCustomer(int departID, int salesID, int custID)
{
	int departmentID, salesmanID, customerID, i;
	departmentID = departID;
	salesmanID = salesID;
	customerID = custID;
	if(customerArray[customerID].privileged)
	{
		Print("DepartmentSalesman [%d] is informed by PrivilegeCustomer [%d] that [item%d] is out of stock.\n",sizeof("DepartmentSalesman [%d] is informed by PrivilegeCustomer [%d] that [item%d] is out of stock.\n"), salesmanID*10000+ customerID, departmentID*10000);
	}
	else
	{
		Print("DepartmentSalesman [%d] is informed by Customer [%d] that [item%d] is out of stock.\n",sizeof("DepartmentSalesman [%d] is informed by Customer [%d] that [item%d] is out of stock.\n"), salesmanID*10000+ customerID, departmentID*10000);
	}
	
	/*debugPrint("A");*/
	AcquireLock(departmentArray[departmentID].restockAlreadyRequestedLock);
	/*debugPrint("B");*/
	if(!departmentArray[departmentID].restockAlreadyRequested)
	{
		/*debugPrint("C - about to acquire salesLoaderRestockLock");*/
		AcquireLock(salesLoaderRestockLock);
		/*debugPrint("acquired salesLoaderRestockLock");*/
		for(i = 0; i<NUM_GOODS_LOADERS; i++)
		{
			if(goodsLoaderStatus[i] == 0)
			{
				departmentArray[departmentID].restockAlreadyRequested = 1;
				salesmanOrderedRestock[i] = salesmanID;
				whichDepartmentToRestock[i] = departmentID;
				goodsLoaderStatus[i] = 1;
				
				/*debugPrint("GoodsLoader0 status: %d",goodsLoaderStatus[i]);*/
				Print("DepartmentSalesman [%d] informs the GoodsLoader [%d] that [item%d] is out of stock.\n",sizeof("DepartmentSalesman [%d] informs the GoodsLoader [%d] that [item%d] is out of stock.\n"), salesmanID*10000+ i, departmentID*10000);
				SignalCondition(goodsLoaderArray[i].goodsLoaderCV,salesLoaderRestockLock);
				break;
			}
		}
		
		if(departmentArray[departmentID].restockAlreadyRequested == 0)
		{
			departmentsToRestock[departmentID] = salesmanID;
			departmentArray[departmentID].restockAlreadyRequested = 1;
		}
		
		/*debugPrint("about to release SLRL GoodsLoader1 status: %d",goodsLoaderStatus[0]);*/
		ReleaseLock(salesLoaderRestockLock);
		/*debugPrint("released SLRL GoodsLoader2 status: %d",goodsLoaderStatus[0]);*/
		/*departmentArray[departmentID].salesStatusArray[salesmanID]=0;*/
	}
	departmentArray[departmentID].salesStatusArray[salesmanID]=0;
	departmentArray[departmentID].whomITalkTo[salesmanID] = -1;
	ReleaseLock(departmentArray[departmentID].restockAlreadyRequestedLock);
	/*departmentArray[departmentID].whomITalkTo[salesmanID] = -1;*/
}

/*This function is called when a Goods Loader returns from restocking. 
	The function is informed by the goods loader  that the item is restocked and does a broadcast to everyone waiting on the restock
*/
void SalesmanLoaderRestock(int departID, int salesID, int goodsID)
{
	int departmentID, salesmanID, loaderID;
	departmentID = departID;
	salesmanID = salesID;
	loaderID = goodsID;
	Print("DepartmentSalesman [%d] is informed by the GoodsLoader [%d] that [item%d] is restocked.\n",sizeof("DepartmentSalesman [%d] is informed by the GoodsLoader [%d] that [item%d] is restocked.\n"), salesmanID*10000+ loaderID, departmentID*10000);
	SignalCondition(departmentArray[departmentID].listOfSalesman[salesmanID].salesmanCV,departmentArray[departmentID].listOfSalesman[salesmanID].salesmanLock);
	Print("DepartmentSalesman [%d] informs the Customers that [item%d] is restocked.\n",sizeof("DepartmentSalesman [%d] informs the Customers that [item%d] is restocked.\n"), salesmanID*10000+ departmentID,-1);
	/*Tells everyone thats waiting for the item restock that it's ready!*/
	AcquireLock(departmentArray[departmentID].departmentRestockLock);
	BroadcastCondition(departmentArray[departmentID].custWaitingForRestockCV,departmentArray[departmentID].departmentRestockLock);
	ReleaseLock(departmentArray[departmentID].departmentRestockLock);
	departmentArray[departmentID].salesStatusArray[salesmanID]=0;
	departmentArray[departmentID].whomITalkTo[salesmanID] = -1;
	AcquireLock(departmentArray[departmentID].restockAlreadyRequestedLock);
	departmentArray[departmentID].restockAlreadyRequested = 0;
	ReleaseLock(departmentArray[departmentID].restockAlreadyRequestedLock);
}

/* The main salesman function that runs when the thread is in the CPU
	This function will:
		1. first attempt to acquire the lock for the line at the sales department counter. 
		2. Check the 'customerWaitingLineCount' monitor variable to check if anyone is in line
			if so, wake up the first guy in the line, decrement the line count, and set status to READY
			if no ones in line, set status to free and continue;+
		3. Acquire my own lock
		4. Release the line lock
		5. Wait for the customer to walk up to me (Sleeps here)
		6. Gets woken up here, use 'whomITalkTo' array to see what type of person we're speaking to
			if '0' - call SalesmanGreetingCustomer();
			if '1' - call SalesmanComplainingCustomer();
			if '2' - call SalesmanLoaderRestock();
		7. If the manager has put me on break, wait on the salesmanOnBreakCV until signaled. 
		8. Release my lock. 
*/
void SalesmanFunction(){
	int departmentID, salesmanID;
	AcquireLock(idLock);
	if(salesmanIDCount == 3)
	{
		departmentIDCount++;
		salesmanIDCount = 0;
	}
	salesmanID = salesmanIDCount;
	departmentID = departmentIDCount;
	salesmanIDCount++;
	ReleaseLock(idLock);

	departmentArray[departmentID].whomITalkTo[salesmanID] = -1;
	while(1)
	{
		AcquireLock(departmentArray[departmentID].goodsLoaderWaitingForSalesLock);
		AcquireLock(departmentArray[departmentID].custWaitingForSalesLock);
		AcquireLock(departmentArray[departmentID].listOfSalesman[salesmanID].salesmanLock);
		if(departmentArray[departmentID].goodsLoaderWaitingLineCount > 0)
		{
			departmentArray[departmentID].salesStatusArray[salesmanID] = 3;
			departmentArray[departmentID].goodsLoaderWaitingLineCount--;
			/*debugPrint("Signaling a waiting goodsloader, status %d, whomITalkTo %d",departmentArray[departmentID].salesStatusArray[salesmanID],departmentArray[departmentID].whomITalkTo[salesmanID]);*/
			SignalCondition(departmentArray[departmentID].goodsLoaderWaitingForSalesCV,departmentArray[departmentID].goodsLoaderWaitingForSalesLock);
			/*departmentArray[departmentID].goodsLoaderWaitingLineCount--;*/
			/*AcquireLock(departmentArray[departmentID].listOfSalesman[salesmanID].salesmanLock);*/
			/*departmentArray[departmentID].salesStatusArray[salesmanID] = 3;*/
			ReleaseLock(departmentArray[departmentID].listOfSalesman[salesmanID].salesmanLock);
		}	/*first acquire the waiting line lock using the department ID we got*/
		else if(departmentArray[departmentID].customerWaitingLineCount > 0){ /*If there are customers in line*/
			/*signal the first customer in line*/
			/*debugPrint("signaling first customer, salesstatus %d",departmentArray[departmentID].salesStatusArray[salesmanID]);*/
			SignalCondition(departmentArray[departmentID].custWaitingForSalesCV,departmentArray[departmentID].custWaitingForSalesLock);
				
			/*debugPrint("has signaled first customer, salesstatus %d",departmentArray[departmentID].salesStatusArray[salesmanID]);*/
			/*remove the customer from the line*/
			departmentArray[departmentID].customerWaitingLineCount--;
			/*debugPrint("Decremented customerWaitingLineCount to ",departmentArray[departmentID].customerWaitingLineCount);*/
			/*sets my status to 3, READY TO SPEAK TO CUSTOMERS*/
			/*debugPrint("now ready to speak to customers, salesstatus %d",departmentArray[departmentID].salesStatusArray[salesmanID]);*/
			/*AcquireLock(departmentArray[departmentID].listOfSalesman[salesmanID].salesmanLock);*/
			departmentArray[departmentID].salesStatusArray[salesmanID] = 3;
			ReleaseLock(departmentArray[departmentID].listOfSalesman[salesmanID].salesmanLock);
		}
		else if (departmentArray[departmentID].salesStatusArray[salesmanID] != 1 && departmentArray[departmentID].whomITalkTo[salesmanID] != 1)
		{	
			/*else, set my status to FREE*/
			/*AcquireLock(departmentArray[departmentID].listOfSalesman[salesmanID].salesmanLock);*/
			/*debugPrint("not busy and not talking to complaining customer, so setting status to free, salesstatus %d, whomITalkTo %d",departmentArray[departmentID].salesStatusArray[salesmanID],departmentArray[departmentID].whomITalkTo[salesmanID]);*/
			departmentArray[departmentID].salesStatusArray[salesmanID] = 0;
			/*debugPrint("salesstatus %d, whomITalkTo %d",departmentArray[departmentID].salesStatusArray[salesmanID],departmentArray[departmentID].whomITalkTo[salesmanID]);*/
			ReleaseLock(departmentArray[departmentID].listOfSalesman[salesmanID].salesmanLock);
		}
		else
		{
			ReleaseLock(departmentArray[departmentID].listOfSalesman[salesmanID].salesmanLock);
		}
		/*acquires the salesman's own lock*/
		
		AcquireLock(departmentArray[departmentID].listOfSalesman[salesmanID].salesmanLock);
		/*release the lock for the line*/
		ReleaseLock(departmentArray[departmentID].goodsLoaderWaitingForSalesLock);
		ReleaseLock(departmentArray[departmentID].custWaitingForSalesLock);
		/*wait for the customer to walk up and talk to me*/
		/*debugPrint("salesmanlock, salesstatus %d, whomITalkTo %d",departmentArray[departmentID].salesStatusArray[salesmanID],departmentArray[departmentID].whomITalkTo[salesmanID]);*/
		
		/*SignalCondition(departmentArray[departmentID].listOfSalesman[salesmanID].salesmanCV,departmentArray[departmentID].listOfSalesman[salesmanID].salesmanLock);*/
		
		if(departmentArray[departmentID].salesStatusArray[salesmanID] != 3 || (departmentArray[departmentID].salesStatusArray[salesmanID] == 3 && departmentArray[departmentID].whomITalkTo[salesmanID]==-1))
		{
			departmentArray[departmentID].salesStatusArray[salesmanID] = 0;
		}
		
		if (departmentArray[departmentID].whomITalkTo[salesmanID]!=1)
		{
			/*debugPrint("line count %d", departmentArray[departmentID].customerWaitingLineCount);*/
			/*debugPrint("waiting on salesmanlock, salesstatus %d, whomITalkTo %d",departmentArray[departmentID].salesStatusArray[salesmanID],departmentArray[departmentID].whomITalkTo[salesmanID]);*/
			SignalCondition(departmentArray[departmentID].listOfSalesman[salesmanID].salesmanCV,departmentArray[departmentID].listOfSalesman[salesmanID].salesmanLock);
			WaitCondition(departmentArray[departmentID].listOfSalesman[salesmanID].salesmanCV,departmentArray[departmentID].listOfSalesman[salesmanID].salesmanLock);
		}
		
		/*debugPrint("woken up, salesstatus %d, whomITalkTo %d",departmentArray[departmentID].salesStatusArray[salesmanID],departmentArray[departmentID].whomITalkTo[salesmanID]);*/
		/*Got woken up here, the customer should have set the whomITalkTo array
		and the salesCustIdentifier/ salesLoaderIdentifier array to pass off the appropriate ID*/
		switch(departmentArray[departmentID].whomITalkTo[salesmanID])
		{
			/*Greeting a customer*/
			case 0:
				SalesmanGreetingCustomer(departmentID, salesmanID, 
					departmentArray[departmentID].salesCustIdentifier[salesmanID]);
				break;
			case 1:
				SalesmanComplainingCustomer(departmentID, salesmanID, 
					departmentArray[departmentID].salesCustIdentifier[salesmanID]);
				break;
			case 2:
				SalesmanLoaderRestock(departmentID, salesmanID, 
					departmentArray[departmentID].salesLoaderIdentifier[salesmanID]);
				break;
			default:
				/*debugPrint("switch defaulting, salesstatus %d, whomITalkTo %d",departmentArray[departmentID].salesStatusArray[salesmanID],departmentArray[departmentID].whomITalkTo[salesmanID]);*/
				break;
		}
		/*debugPrint("after switch, salesstatus %d, whomITalkTo %d",departmentArray[departmentID].salesStatusArray[salesmanID],departmentArray[departmentID].whomITalkTo[salesmanID]);*/
		if(departmentArray[departmentID].listOfSalesman[salesmanID].goOnBreak)
		{
			/*If we get here, the manager has put me on break;*/
			departmentArray[departmentID].salesStatusArray[salesmanID] = 2;
			WaitCondition(departmentArray[departmentID].listOfSalesman[salesmanID].salesmanOnBreakCV,departmentArray[departmentID].listOfSalesman[salesmanID].salesmanLock);
			departmentArray[departmentID].listOfSalesman[salesmanID].goOnBreak = 0;
			departmentArray[departmentID].salesStatusArray[salesmanID] = 0;
		}
		/*Release the Lock, task done*/
		ReleaseLock(departmentArray[departmentID].listOfSalesman[salesmanID].salesmanLock);
	}
	Exit(0);
}

/*DepartmentSetup function, initializes variables in each department*/
void DepartmentSetup(int id){
	int j;
	departmentArray[id].identifier = id; /*incremented after salesman loop*/
	departmentArray[id].numberOfItems = NUM_ITEMS_ON_SHELF;
	departmentArray[id].customerWaitingLineCount = 0;
	departmentArray[id].goodsLoaderWaitingLineCount = 0;
	departmentArray[id].restockAlreadyRequested = 0;
	/*initializes the 3 salesmen that wil be working in the department*/
	for(j = 0; j < NUM_SALESMAN; j++)
	{
		departmentArray[id].salesStatusArray[j] = 1;
		departmentArray[id].whomITalkTo[j] = -1;
		SalesmanSetup(j, id);
		departmentArray[id].salesCustIdentifier[j] = -1;
	}
	
	/*initializes the lock for the goods loaders waiting in the sales line*/
	departmentArray[id].departmentRestockLock = CreateLock("Department Restock Lock", sizeof("Department Restock Lock"));
	
	/*initializes the lock for the goods loaders waiting in the sales line*/
	departmentArray[id].restockAlreadyRequestedLock = CreateLock("Restock Already Requested Lock", sizeof("Restock Already Requested Lock"));
	
	/*initializes the lock for the goods loaders waiting in the sales line*/
	departmentArray[id].goodsLoaderWaitingForSalesLock = CreateLock("Goods Loader Sales Department Line Lock", sizeof("Goods Loader Sales Department Line Lock"));
	
	/*initializes the lock for the customers waiting in the sales line*/
	departmentArray[id].custWaitingForSalesLock = CreateLock("Sales Department Line Lock", sizeof("Sales Department Line Lock"));
	
	/*initializes the lock for the customers waiting in the sales line*/
	departmentArray[id].shelfLock = CreateLock("Sales Department Shelf Lock", sizeof("Sales Department Shelf Lock"));
	
	/*initializes the condition variable for goods loaders waiting in the sales line*/
	departmentArray[id].goodsLoaderWaitingForSalesCV = CreateCondition("Goods Loader Sales Department Line CV", sizeof("Goods Loader Sales Department Line CV"));
	
	/*initializes the condition variable for customers waiting in the sales line*/
	departmentArray[id].custWaitingForSalesCV = CreateCondition("Sales Department Line CV", sizeof("Sales Department Line CV"));
	
	
	/*initializes the condition variable for customers waiting in the sales line*/
	departmentArray[id].custWaitingForRestockCV = CreateCondition("Sales Department restock CV", sizeof("Sales Department restock CV"));
	
	/*initializes the condition variable for customers waiting in the sales line*/
	departmentArray[id].shelfCV = CreateCondition("Sales Department Shelf CV", sizeof("Sales Department Shelf CV"));
}
/*=================================================//*/
/*----------------(END) SALESMAN-------------------//*/
/*=================================================//*/

/*=================================================//*/
/*--------------------MANAGER----------------------//*/
/*=================================================//*/
/*Setup function for the manager: initializes variables in manager*/
void ManagerSetup()
{
	manager.currentCashierID = -1;
	manager.totalSales = 0;
	manager.itemToRemove = -1;
	manager.steps = 0;
	manager.stepsUntilEmptyingDrawers = 100;
	manager.stepsUntilStatingTotalSales = randInt(1,200);
	manager.stepsUntilSendingCashierOnBreak = randInt(1,20);
	manager.stepsUntilSendingSalesmanOnBreak = randInt(1,1000);
	
	/*initializes the lock for talking to the manager*/
	manager.managerLock = CreateLock("manager Lock", sizeof("manager Lock"));
	
	/*initializes the condition variable for talking to the manager*/
	manager.managerCV = CreateCondition("Manager CV", sizeof("Manager CV"));
	
	/*initializes the condition variable for interaction between manager/cashiers*/
	manager.managerCashierLineCV = CreateCondition("Manager Cashier Line CV", sizeof("Manager Cashier Line CV"));
	
	/*initializes the condition variable for interaction between manager/cashiers*/
	manager.managerCashierHelpCV = CreateCondition("Manager Cashier Help CV", sizeof("Manager Cashier Help CV"));
}
void ManagerEmptyDrawers()
{
	int i;
	for (i = 0; i < NUM_CASHIERS; i++)
	{
		AcquireLock(checkoutCounterArray[i].drawerLock);
		manager.totalSales += checkoutCounterArray[i].moneyInDrawer;
		checkoutCounterArray[i].moneyInDrawer = 0;
		Print("Manager emptied Counter [%d] drawer.\n",sizeof("Manager emptied Counter [%d] drawer.\n"),i*10000,-1);
		PrintString("Manager has total sale of $[", sizeof("Manager has total sale of $["));
		convertToDollarsAndCents(manager.totalSales);
		PrintString("].\n", sizeof("].\n"));
		ReleaseLock(checkoutCounterArray[i].drawerLock);
	}
}
void ManagerSendCashierOnBreak()
{
	int i;
	int sentSomeoneOnBreak = 0;
	int cashierToSendOnBreak = -1;
	int cashiersOnBreak = 0;
	for (i = 0; i < NUM_CASHIERS; i++)
	{
		/*AcquireLock(cashierArray[i].cashierLock);*/
		if (!sentSomeoneOnBreak && cashierArray[i].goOnBreak != 1) /*&& (cashierArray[i].cashierLineCount+cashierArray[i].cashierPrivilegedLineCount)<=1)*/
		{
			cashierToSendOnBreak = i;
			sentSomeoneOnBreak = 1;
		}
		else if (cashierArray[i].goOnBreak == 1)
		{
			cashiersOnBreak++;
		}
		/*ReleaseLock(cashierArray[i].cashierLock);*/
	}
	if (cashiersOnBreak < NUM_CASHIERS-1)
	{
		/*AcquireLock(cashierArray[cashierToSendOnBreak].cashierLock);*/
		AcquireLock(cashierArray[cashierToSendOnBreak].checkOrModifyLinesLock);
		cashierArray[cashierToSendOnBreak].goOnBreak = 1;
		/*AcquireLock(cashierArray[cashierToSendOnBreak].checkOrModifyLinesLock);*/
		if(cashierArray[cashierToSendOnBreak].servingCustomer == 0)
		{
			AcquireLock(cashierArray[cashierToSendOnBreak].cashierLock);
			SignalCondition(cashierArray[cashierToSendOnBreak].cashierCV,cashierArray[cashierToSendOnBreak].cashierLock);
			ReleaseLock(cashierArray[cashierToSendOnBreak].cashierLock);
		}
		else 
		{
			/*debugPrint("servingCustomer, id:",cashierArray[cashierToSendOnBreak].servingCustomer,cashierArray[cashierToSendOnBreak].customerID);*/
		}
		ReleaseLock(cashierArray[cashierToSendOnBreak].checkOrModifyLinesLock);
		Print("Manager sends Cashier [%d] on break.\n",sizeof("Manager sends Cashier [%d] on break.\n"),cashierToSendOnBreak*10000,-1);
		/*ReleaseLock(cashierArray[cashierToSendOnBreak].cashierLock);*/
	}
}
void ManagerSendSalesmanOnBreak()
{
	int i;
	int sentSomeoneOnBreak = 0;
	int salesmanToSendOnBreak = -1;
	int salesmansOnBreak = 0;
	int department = randInt(0,NUM_DEPARTMENTS-1);
	for (i = 0; i < NUM_SALESMAN; i++)
	{
		if (!sentSomeoneOnBreak && departmentArray[department].salesStatusArray[i] != 2)
		{
			salesmanToSendOnBreak = i;
			sentSomeoneOnBreak = 1;
		}
		else if (departmentArray[department].salesStatusArray[i] == 2)
		{
			salesmansOnBreak++;
		}
	}
	if (salesmansOnBreak < NUM_SALESMAN-1)
	{
		AcquireLock(departmentArray[department].listOfSalesman[salesmanToSendOnBreak].salesmanLock);
		departmentArray[department].salesStatusArray[salesmanToSendOnBreak] = 2;
		Print("Manager sends DepartmentSalesman [%d] of Department [%d] on break.\n",sizeof("Manager sends DepartmentSalesman [%d] of Department [%d] on break.\n"),salesmanToSendOnBreak*10000+department,-1);
		ReleaseLock(departmentArray[department].listOfSalesman[salesmanToSendOnBreak].salesmanLock);
	}
}
void ManagerBringSalesmanBackFromBreak()
{
	int h, i;
	for (h = 0; h < NUM_DEPARTMENTS; h++)
	{
		for (i = 0; i < NUM_SALESMAN; i++)
		{
			AcquireLock(departmentArray[h].listOfSalesman[i].salesmanLock);
			if (departmentArray[h].salesStatusArray[i] == 2)
			{
				
				SignalCondition(departmentArray[h].listOfSalesman[i].salesmanOnBreakCV,departmentArray[h].listOfSalesman[i].salesmanLock);
				departmentArray[h].salesStatusArray[i] = 0;
				Print("Manager brings back DepartmentSalesman [%d] of Department [%d] from break.\n",sizeof("Manager brings back DepartmentSalesman [%d] of Department [%d] from break.\n"),i*10000+h,-1);
				ReleaseLock(departmentArray[h].listOfSalesman[i].salesmanLock);
			}
			else
			{
				ReleaseLock(departmentArray[h].listOfSalesman[i].salesmanLock);
			}
		}
	}
}
void ManagerBringCashiersBackFromBreak()
{
	int i;
	for (i = 0; i < NUM_CASHIERS; i++)
	{
		if (cashierArray[i].goOnBreak && cashierArray[i].onBreak)
		{
			AcquireLock(cashierArray[i].cashierLock);
			cashierArray[i].goOnBreak = 0;
			SignalCondition(cashierArray[i].cashierCV,cashierArray[i].cashierLock);
			Print("Manager brings back Cashier [%d] from break.\n",sizeof("Manager brings back Cashier [%d] from break.\n"),i*10000,-1);
			ReleaseLock(cashierArray[i].cashierLock);
		}
	}
}
int ManagerSeesThatCashierLinesAreTooLong()
{
	int i;
	int endBreaks = 0;
	int cashierToSendOnBreak = -1;
	int cashiersOnBreak = 0;
	for (i = 0; i < NUM_CASHIERS; i++)
	{
		if ((cashierArray[i].cashierLineCount+cashierArray[i].cashierPrivilegedLineCount)>=3)
		{
			endBreaks = 1;
		}
	}
	return endBreaks;
}
void ManagerFunction()
{
	/*All manager code goes here*/
	/*while(1){Yield();	printf("hello\n");	}	*/
	while (remainingCustomers != 0&& manager.steps<100000)
	{
		manager.steps++;
		/*this loop will run between 200 and 1000 times for 10-30 customers*/
		if (manager.currentCashierID == -1)
		{
			AcquireLock(manager.managerLock);
			manager.stepsUntilSendingCashierOnBreak--;
			manager.stepsUntilSendingSalesmanOnBreak--;
			manager.stepsUntilEmptyingDrawers--;
			manager.stepsUntilStatingTotalSales--; 
			if (manager.stepsUntilSendingCashierOnBreak <= 0)
			{
				/*/*debugPrint("manager.stepsUntilSendingCashierOnBreak",manager.stepsUntilSendingCashierOnBreak);*/
				manager.stepsUntilSendingCashierOnBreak = randInt(1,20);
				/*/*debugPrint("manager.stepsUntilSendingCashierOnBreak",manager.stepsUntilSendingCashierOnBreak);*/
				/*if (randInt(1,10)<9)*/
					ManagerSendCashierOnBreak();
				/*else*/
					/*ManagerBringCashiersBackFromBreak();*/
			}
			if (manager.stepsUntilSendingSalesmanOnBreak <= 0)
			{
				manager.stepsUntilSendingSalesmanOnBreak = randInt(1,1000);
				if (randInt(1,10)<9)
					ManagerSendSalesmanOnBreak();
				else
					ManagerBringSalesmanBackFromBreak();
			}
			if (manager.stepsUntilEmptyingDrawers <= 0)
			{
				manager.stepsUntilEmptyingDrawers = 100;
				ManagerEmptyDrawers();
			}
			if (manager.stepsUntilStatingTotalSales <= 0)
			{
				manager.stepsUntilStatingTotalSales = randInt(1,200);
				PrintString("-------Total Sale of the entire store until now is $[", sizeof("-------Total Sale of the entire store until now is $["));
				convertToDollarsAndCents(manager.totalSales);
				PrintString("]---------\n", sizeof("]---------\n"));
			}
			if (ManagerSeesThatCashierLinesAreTooLong())
				ManagerBringCashiersBackFromBreak();
			
			Yield();
			/*/*debugPrint("A");*/
			ReleaseLock(manager.managerLock);
			/*/*debugPrint("B");*/
		}
		else if(customerArray[cashierArray[manager.currentCashierID].customerID].readyToNegotiate == 1) /*handling a customer who cannot afford items*/
		{
			/*debugPrint("acquiring manager lock to help customer");*/
			AcquireLock(manager.managerLock);
			/*debugPrint("acquired manager lock to help customer");*/
			
			manager.itemToRemove = -1;
			while(manager.itemToRemove != -2)
			{
				if(manager.itemToRemove == -1)
				{
					/*debugPrint("signaling customer to negotiate");*/
					SignalCondition(manager.managerCV,manager.managerLock); /*tell customer manager is ready to negotiate*/
				}
				
				/*debugPrint("waiting for customer to pick next item to remove or pay");*/
				WaitCondition(manager.managerCV,manager.managerLock); /*wait for customer to pick an item to remove or pay if enough items have been removed*/
				/*debugPrint("customer to picked next item or paid");*/
				
				if(manager.itemToRemove != -2)
				{
					/*prints that manager removed an item from the customer's trolly*/
					if(customerArray[cashierArray[manager.currentCashierID].customerID].privileged)
						Print("Manager removes [item%d] from the trolly of PrivilegeCustomer [%d].\n",sizeof("Manager removes [item%d] from the trolly of PrivilegeCustomer [%d].\n"), manager.itemToRemove*10000+ cashierArray[manager.currentCashierID].customerID,-1);
					else
						Print("Manager removes [item%d] from the trolly of Customer [%d].\n",sizeof("Manager removes [item%d] from the trolly of Customer [%d].\n"), manager.itemToRemove*10000+ cashierArray[manager.currentCashierID].customerID,-1);
				
					SignalCondition(manager.managerCV,manager.managerLock); /*tell customer item has been removed*/
				}
			}
						
			/*Prints that customer transaction was completed by manager*/
			if(customerArray[cashierArray[manager.currentCashierID].customerID].privileged)
				Print("Manager gave the receipt to PrivilegedCustomer [%d] and tells him to leave.\n",sizeof("Manager gave the receipt to PrivilegedCustomer [%d] and tells him to leave.\n"), cashierArray[manager.currentCashierID].customerID*10000,-1);
			else
				Print("Manager gave the receipt to Customer [%d] and tells him to leave.\n",sizeof("Manager gave the receipt to Customer [%d] and tells him to leave.\n"), cashierArray[manager.currentCashierID].customerID*10000,-1);
			
			SignalCondition(manager.managerCV,manager.managerLock); /*give receipt to customer and tell him to leave*/
			
			SignalCondition(manager.managerCashierHelpCV,manager.managerLock); /*tell current cashier that transaction has completed*/
			SignalCondition(manager.managerCashierLineCV,manager.managerLock); /*tell next waiting cashier that the manager is now free to help more customers*/
			manager.currentCashierID = -1;
			ReleaseLock(manager.managerLock);
		}
		/*/*debugPrint("C");*/
		/*Yield();*/
		/*/*debugPrint("D");*/
		
		Yield();
	}
	if (remainingCustomers==0)
	{
		ManagerEmptyDrawers();
		printEndOfSimulationOutputs();
		/*debugPrint("Steps: ",manager.steps);*/
	}
	else
	{
		/*debugPrint("Timeout! Steps: ",manager.steps);*/
		/*debugPrint("RemainingCustomers: ",remainingCustomers);*/
	}
	Exit(0);
}
/*=================================================//*/
/*-----------------(END) MANAGER-------------------//*/
/*=================================================//*/

/*=================================================//*/
/*---------------SETUP FUNCTION--------------------//*/
/*=================================================//*/
void Setup(int numCashiers, int numLoaders, int numDepartments, int numSalesman, int numCustomers, int seedBasedOnTime, int customerMoney, int itemsOnShelf){
	int i, j;
	
	stockRoomLock = CreateLock("StockRoom Lock", sizeof("StockRoom Lock"));
	trollyLineLock = CreateLock("Trolly Line Lock", sizeof("Trolly Line Lock"));
	trollyLineCV = CreateCondition("Trolly Line CV", sizeof("Trolly Line CV"));
	cashierLinesLock = CreateLock("Cashier Lines Lock", sizeof("Cashier Lines Lock"));
	salesLoaderRestockLock = CreateLock("Sales Loader Restock Lock", sizeof("Sales Loader Restock Lock"));
	idLock = CreateLock("ID Assignment Lock", sizeof("ID Assignment Lock"));
	
	NUM_GOODS_LOADERS = numLoaders;
	NUM_MANAGERS = 1;
	NUM_SALESMAN = numSalesman;
	NUM_DEPARTMENTS = numDepartments;
	NUM_TOTAL_CUSTOMERS = numCustomers;
	NUM_CASHIERS = numCashiers;
	NUM_ITEMS_ON_SHELF = itemsOnShelf;
	remainingCustomers = numCustomers;
	
	if(seedBasedOnTime)
	{
		SRand();
		/*srand(time(NULL)); /*generates a seed for rand() based on time*/
	}
	else
	{
		SRand();
		/*srand(1); /*sets seed for rand() to 1 (useful for getting consistent results when testing)*/
	}
	
	if(customerMoney == -1)
	{
		/*customer brings a minimum of 15 dollars and a*/
		/*maximum of 10 times the price of the most*/
		/*expensive item possible*/
		CUSTOMER_MONEY = randInt(1500, 1000*MAX_PRICE);
	}
	else
		CUSTOMER_MONEY = customerMoney;
	
	for(i = 0; i < numDepartments; i++)
	{
		pricesOfItems[i] = randInt(MIN_PRICE*100, MAX_PRICE*100);
		DepartmentSetup(i);
		departmentsToRestock[i] = -1;
	}

	for(i = 0; i < numCustomers; i++)
	{
		CustomerSetup(i);
	}

	for(i = 0; i < numCashiers; i++)
	{
		CashierSetup(i);
		CheckoutCounterSetup(i);
	}

	/*sets up the goodsloaders and their array.*/
	for(i = 0; i < numLoaders; i++) 
	{
		GoodsLoaderSetup(i);
	}
	
	/*sets up the manager*/
	ManagerSetup();
	
	Print("Number of Cashiers = [%d]\n",sizeof("Number of Cashiers = [%d]\n"), numCashiers*10000,-1);
	Print("Number of Goods Loaders = [%d]\n",sizeof("Number of Goods Loaders = [%d]\n"), numLoaders*10000,-1);
	Print("Number of PrivilegedCustomers = [%d]\n",sizeof("Number of PrivilegedCustomers = [%d]\n"), NUM_PRIVILEGED_CUSTOMERS*10000,-1);
	Print("Number of Customers = [%d]\n",sizeof("Number of Customers = [%d]\n"), NUM_CUSTOMERS*10000,-1);
	PrintString("Number of Managers = [1]\n", sizeof("Number of Managers = [1]\n"));
	Print("Number of Departments = [%d]\n",sizeof("Number of Departments = [%d]\n"), numDepartments*10000,-1);
	Print("Number of DepartmentSalesmen per department = [%d]\n",sizeof("Number of DepartmentSalesmen per department = [%d]\n"), numSalesman*10000,-1);
	PrintString("      Items:\n", sizeof("      Items:\n"));
	PrintString("         Number - Price\n", sizeof("         Number - Price\n"));
	for(i = 0; i < numDepartments; i++)
	{
		Print("            [%d] - $[", sizeof("            [%d] - $["), i*10000, -1);
		convertToDollarsAndCents(pricesOfItems[i]);
		PrintString("]\n", sizeof("]\n"));
	}
	PrintString("\n", sizeof("\n"));
	
	/*Fork all threads*/
	for(i = 0; i < numCustomers; i++)
	{
		Fork(CustomerFunction, "Customer", sizeof("Customer"));
	}
	
	for(i = 0; i<numCashiers; i++)
	{
		Fork(CashierFunction, "Cashier", sizeof("Cashier"));
	}

	/*Spawns salesmen for each department*/
	for(i = 0; i < numDepartments; i++)
	{
		/*for each department, spawn 3 salesmen*/
		for(j = 0; j < numSalesman; j++)
		{
			Fork(SalesmanFunction, "Salesman", sizeof("Salesman"));
		}
	}
	for(i = 0; i<numLoaders; i++)
	{
		Fork(GoodsLoaderFunction, "GoodsLoader", sizeof("GoodsLoader"));
	}
	
	Fork(ManagerFunction, "Manager", sizeof("Manager"));
}
/*=================================================//*/
/*------------(END) SETUP FUNCTION-----------------//*/
/*=================================================//*/

/*ValidateInput function that takes in the prompt, the error msg */
/*and the range of numbers that restricts the amount of each person you may have.*/
int ValidateInput(char* prompt, char* errorMsg, int min, int max)
{
	int userInput;
	char temp[256];
	while (1)
	{
		/*printf("%s\n", prompt);*/
		PrintString(prompt, sizeof(prompt));
		PrintString("\n", sizeof("\n"));
		Scan(temp, 256);
		userInput = Atoi(temp, 256);
		if (userInput >= min && userInput <= max)
		{
			return userInput;
		}
		else
		{
			PrintString(errorMsg, sizeof(errorMsg));
			PrintString("\n", sizeof("\n"));
		}
	}
}

/*Calls ValidateInput to have the users initialize the number of each person to be in the super market simulation*/
void Test11Initialize()
{	
	NUM_CASHIERS = ValidateInput("Please enter the number of cashiers: \n", "ERROR: The number of cashiers must be between 1-5\n\n", 1, MAX_CASHIERS);
	NUM_GOODS_LOADERS = ValidateInput("Please enter the number of goods loaders: \n", "ERROR: The number of goods loaders must be between 1-5\n\n", 1, MAX_GOODS_LOADERS);
	NUM_DEPARTMENTS = ValidateInput("Please enter the number of departments: \n", "ERROR: The number of departments must be between 1-5\n\n", 1, MAX_DEPARTMENTS);
	NUM_SALESMAN = ValidateInput("Please enter the number of salesman per department: \n", "ERROR: The number of salesman per department must be between 1-3\n", 1, MAX_SALESMAN);
	NUM_TOTAL_CUSTOMERS = ValidateInput("Please enter the number of customers: \n", "ERROR: The number of customers must be between 1-30\n", 1, MAX_CUSTOMERS);
	
	Setup(NUM_CASHIERS, NUM_GOODS_LOADERS, NUM_DEPARTMENTS, NUM_SALESMAN, NUM_TOTAL_CUSTOMERS, 1, -1, 10);
}

/************************************************************************************/
/******************************TESTS BELOW THIS LINE*********************************/
/************************************************************************************/
/* --------------------------------------------------*/
/* Problem2*/
/* --------------------------------------------------*/
	int main()
	{
		Setup(1,1,1,1,2, 0, -1, 10);
		Exit(0);
	}

/*=================================================//*/
/*--------------PART 2 TEST SUITES-----------------//*/
/*=================================================//*/
/*---------------------------------------------------
 TEST1- Test1CustomerAlwaysTakesShortestLine
 This test will prove that customers always take the
 shortest line but no 2 customers ever choose the same
 shortest line at the same time.
---------------------------------------------------*/
void Test1CustomerAlwaysTakesShortestLine()
{
	PrintString("Executing Test [1].\n\n", sizeof("Executing Test [1].\n\n"));
	Setup(5,1,1,3,30, 0, -1, 300);
}

/*---------------------------------------------------
 TEST2- Test2ManagerOnlyTalksToOnePerson
Managers can only talk to one Cashier, or one Customer, 
at a time.
----------------------------------------------------*/
void Test2ManagerOnlyTalksToOnePerson()
{
	PrintString("Executing Test [2].\n\n", sizeof("Executing Test [2].\n\n"));
	Setup(5,3,1,3,10, 0, 0, 300);
}

/*---------------------------------------------------
 TEST3- Test3CustomerDoesNotLeaveWithoutReceipt
 Customers do not leave until they are given 
 their receipt by the Cashier. The Cashier does not start 
 on another customer until they know that the last 
 Customer has left their area.
----------------------------------------------------*/
void Test3CustomerDoesNotLeaveWithoutReceipt()
{
	PrintString("Executing Test [3].\n\n", sizeof("Executing Test [3].\n\n"));
	Setup(1,1,1,1,2, 0, -1, 10);
}

/*---------------------------------------------------
 TEST4- Test4CashierScansTillTrollyEmpty
Cashier scans the items till the trolly is empty.
----------------------------------------------------*/
void Test4CashierScansTillTrollyEmpty()
{
	PrintString("Executing Test [4].\n\n", sizeof("Executing Test [4].\n\n"));
	Setup(1,1,1,1,1, 0, -1, 10);
}

/*---------------------------------------------------
 TEST5- Test5CashierSentOnBreakByManager
Cashiers are sent on break by the Manager randomly.
----------------------------------------------------*/
void Test5CashierSentOnBreakByManager()
{
	PrintString("Executing Test [5].\n\n", sizeof("Executing Test [5].\n\n"));
	Setup(5,5,5,3,30, 0, -1, 10);
}

/*---------------------------------------------------
 TEST6- Test6ManagerGetsCashiersOffBreak
Managers get Cashiers off their break when lines 
have 3, or more, Customers.
----------------------------------------------------*/
void Test6ManagerGetsCashiersOffBreak()
{
	PrintString("Executing Test [6].\n\n", sizeof("Executing Test [6].\n\n"));
	Setup(5,5,5,3,30, 0, -1, 10);
}

/*---------------------------------------------------
 TEST7- Test7TotalSalesNoRaceCondition
Total sales never suffers from a race condition.
----------------------------------------------------*/
void Test7TotalSalesNoRaceCondition()
{
	PrintString("Executing Test [7].\n\n", sizeof("Executing Test [7].\n\n"));
	Setup(5,5,5,3,30, 0, -1, 10);
}

/*---------------------------------------------------
 TEST8- Test8GoodsLoaderCustomerShelfAccess
Goods Loader don't try to restock an item on a shelf 
when a Customer is trying to take an item off the shelf.
----------------------------------------------------*/
void Test8GoodsLoaderCustomerShelfAccess()
{
	PrintString("Executing Test [8].\n\n", sizeof("Executing Test [8].\n\n"));
	Setup(1,3,1,3,30, 0, -1, 1);
}

/*---------------------------------------------------
 TEST9- Test9OneGoodsLoaderInStockRoom
Only one Goods Loader enters the stock room at a time.
----------------------------------------------------*/
void Test9OneGoodsLoaderInStockRoom()
{
	PrintString("Executing Test [9].\n\n", sizeof("Executing Test [9].\n\n"));
	Setup(5,5,3,3,30, 0, -1, 10);
}

/*---------------------------------------------------
 TEST10- Test10CustomerWaitsForItemRestock
Customers wait for items to be restocked 
- when told by the Department Salesman.
----------------------------------------------------*/
void Test10CustomerWaitsForItemRestock()
{
	PrintString("Executing Test [10].\n\n", sizeof("Executing Test [10].\n\n"));
	Setup(5,5,3,3,30, 0, -1, 10);
}

/*===================================================
 StartTests function which will display a menu for the 
 super market simulation.
===================================================*/
int StartTests()
{
	char temp[256]; /*Initialize some variables to use for validating the user input.*/
	char tempInt[256];
	int userInput;
	int min = 1;
	int max = 10;
	/*Prints out the menu*/
	PrintString("===========================================\n\n", sizeof("===========================================\n\n"));
	PrintString("==SUPER MARKET SIMULATION TEST SUITE MENU==\n\n", sizeof("==SUPER MARKET SIMULATION TEST SUITE MENU==\n\n"));
	PrintString("===========================================\n\n", sizeof("===========================================\n\n"));
	PrintString("[1] Customers always take the shortest line, but no 2 customers ever choose the same shortest line at the same time.\n\n", sizeof("[1] Customers always take the shortest line, but no 2 customers ever choose the same shortest line at the same time.\n\n"));
	PrintString("[2] Managers can only talk to one Cashier, or one Customer, at a time.\n\n", sizeof("[2] Managers can only talk to one Cashier, or one Customer, at a time.\n\n"));
	PrintString("[3] Customers do not leave until they are given their receipt by the Cashier. The Cashier does not start on another customer until they know that the last Customer has left their area.\n\n", sizeof("[3] Customers do not leave until they are given their receipt by the Cashier. The Cashier does not start on another customer until they know that the last Customer has left their area.\n\n"));
	PrintString("[4] Cashier scans the items till the trolly is empty.\n\n", sizeof("[4] Cashier scans the items till the trolly is empty.\n\n"));
	PrintString("[5] Cashiers are sent on break by the Manager randomly.\n\n", sizeof("[5] Cashiers are sent on break by the Manager randomly.\n\n"));
	PrintString("[6] Managers get Cashiers off their break when lines have 3, or more, Customers.\n\n", sizeof("[6] Managers get Cashiers off their break when lines have 3, or more, Customers.\n\n"));
	PrintString("[7] Total sales never suffers from a race condition.\n\n", sizeof("[7] Total sales never suffers from a race condition.\n\n"));
	PrintString("[8] Goods Loader don't try to restock an item on a shelf when a Customer is trying to take an item off the shelf.\n\n", sizeof("[8] Goods Loader don't try to restock an item on a shelf when a Customer is trying to take an item off the shelf.\n\n"));
	PrintString("[9] Only one Goods Loader enters the stock room at a time.\n\n", sizeof("[9] Only one Goods Loader enters the stock room at a time.\n\n"));
	PrintString("[10] Customers wait for items to be restocked - when told by the Department Salesman.\n\n", sizeof("[10] Customers wait for items to be restocked - when told by the Department Salesman.\n\n"));
	/*PrintString("[11] Simulate the supermarket with a custom number of cashiers, goods loaders, departments, salesmen, and customers.\n     NOTE: For this test, the number of items a customer wants and the price of each item is set randomly.\n\n", sizeof());*/
	PrintString("===========================================\n\n", sizeof("===========================================\n\n"));
	PrintString("===========END TEST SUITE MENU=============\n\n", sizeof("===========END TEST SUITE MENU=============\n\n"));
	PrintString("===========================================\n\n", sizeof("===========================================\n\n"));
	/*Enter the input validation loop here*/
	while (1)
	{
		PrintString("PLEASE ENTER THE NUMBER OF YOUR CHOICE: \n", sizeof("PLEASE ENTER THE NUMBER OF YOUR CHOICE: \n"));
		Scan(tempInt, 256);
		/*cin>>temp;*/
		userInput=Atoi(tempInt, 256);
		/*userInput = Atoi(temp, sizeof(temp));*/
		Print("YOU ENTERED [%d].\n\n",sizeof("YOU ENTERED [%d].\n\n"), userInput*10000,-1);
		if (userInput >= min && userInput <= max)
		{
			/*if the input is in the correct range, break out of this loop. */
			break;
		}
		else
		{
			PrintString("PLEASE ENTER A NUMBER BETWEEN 1-10\n\n\n", sizeof("PLEASE ENTER A NUMBER BETWEEN 1-10\n\n\n"));
		}
	}
	/*This is a giant if else statement to choose which test to run.*/
	if(userInput == 1)
	{
		Test1CustomerAlwaysTakesShortestLine();
	}
	else if(userInput == 2)
	{
		Test2ManagerOnlyTalksToOnePerson();
	}
	else if(userInput == 3)
	{
		Test3CustomerDoesNotLeaveWithoutReceipt();
	}
	else if(userInput == 4)
	{
		Test4CashierScansTillTrollyEmpty();
	}
	else if(userInput == 5)
	{
		Test5CashierSentOnBreakByManager();
	}
	else if(userInput == 6)
	{
		Test6ManagerGetsCashiersOffBreak();
	}
	else if(userInput == 7)
	{
		Test7TotalSalesNoRaceCondition();
	}
	else if(userInput == 8)
	{
		Test8GoodsLoaderCustomerShelfAccess();
	}
	else if(userInput == 9)
	{
		Test9OneGoodsLoaderInStockRoom();
	}
	else if(userInput == 10)
	{
		Test10CustomerWaitsForItemRestock();
	}
	/*else if(userInput == 11)
	{
		Test11Initialize();
	}*/

	return 1;
}

/*=================================================//*/
/*-----------(END) PART 2 TEST SUITES--------------//*/
/*=================================================//*/
